diff --git a/.github/workflows/run-javascript-tests.yml b/.github/workflows/run-javascript-tests.yml index 5afe28813..cf899a1a2 100644 --- a/.github/workflows/run-javascript-tests.yml +++ b/.github/workflows/run-javascript-tests.yml @@ -36,4 +36,4 @@ jobs: - name: Run the tests run: | cd web - yarn run test:karma-once + yarn run test:js-once diff --git a/Dockerfile b/Dockerfile index 1526462cc..ab08b6487 100644 --- a/Dockerfile +++ b/Dockerfile @@ -55,7 +55,8 @@ RUN export CPPFLAGS="-DPNG_ARM_NEON_OPT=0" && \ .[^.]* \ babel.cfg \ webpack.* \ - karma.conf.js \ + jest.config.js \ + babel.* \ ./pgadmin/static/js/generated/.cache ######################################################################### diff --git a/Makefile b/Makefile index 61dfd7807..874661a6e 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ linter: cd web && yarn run linter check: install-node bundle linter check-pep8 - cd web && yarn run karma start --single-run && python regression/runtests.py + cd web && yarn run test:js-once && python regression/runtests.py check-audit: cd web && yarn run audit @@ -77,10 +77,10 @@ check-feature: install-node bundle cd web && python regression/runtests.py --pkg feature_tests check-js: install-node linter - cd web && yarn run karma start --single-run + cd web && yarn run test:js-once check-js-coverage: - cd web && yarn run test:karma-coverage + cd web && yarn run test:js-coverage # Include all clean sub-targets in clean clean: clean-appbundle clean-debian clean-dist clean-docs clean-node clean-pip clean-redhat clean-src diff --git a/README.md b/README.md index d2c503884..39b9e4cf9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# pgAdmin 4 +# pgAdmin 4 pgAdmin 4 is a rewrite of the popular pgAdmin3 management tool for the -PostgreSQL (http://www.postgresql.org) database. +PostgreSQL (http://www.postgresql.org) database. In the following documentation and examples, *$PGADMIN4_SRC/* is used to denote the top-level directory of a copy of the pgAdmin source tree, either from a @@ -9,9 +9,8 @@ tarball or a git checkout. ## Architecture -pgAdmin 4 is written as a web application in Python, using jQuery and Bootstrap -for the client side processing and UI. On the server side, Flask is being -utilised. +pgAdmin 4 is written as a web application with Python(Flask) on the server side +and ReactJS, HTML5 with CSS for the client side processing and UI. Although developed using web technologies, pgAdmin 4 can be deployed either on a web server using a browser, or standalone on a workstation. The runtime/ @@ -22,7 +21,7 @@ which will execute the Python server and display the UI. To build the runtime, the following packages must be installed: -* NodeJS 12+ +* NodeJS 16+ * Yarn Change into the runtime directory, and run *yarn install*. This will install the @@ -59,20 +58,20 @@ simple - adapt as required for your distribution: ```bash $ python3 -m venv venv ``` - + 2. Now activate the virtual environment: ```bash $ source venv/bin/activate ``` - + 3. Some of the components used by pgAdmin require a very recent version of *pip*, so update that to the latest: - + ```bash $ pip install --upgrade pip ``` - + 4. Ensure that a PostgreSQL installation's bin/ directory is in the path (so pg_config can be found for building psycopg3), and install the required packages: @@ -80,20 +79,20 @@ simple - adapt as required for your distribution: ```bash (venv) $ PATH=$PATH:/usr/local/pgsql/bin pip install -r $PGADMIN4_SRC/requirements.txt ``` - + If you are planning to run the regression tests, you also need to install additional requirements from web/regression/requirements.txt: ```bash (venv) $ pip install -r $PGADMIN4_SRC/web/regression/requirements.txt ``` - + 5. Create a local configuration file for pgAdmin. Edit $PGADMIN4_SRC/web/config_local.py and add any desired configuration options (use the config.py file as a reference - any settings duplicated in config_local.py will override those in config.py). A typical development configuration may look like: - + ```python from config import * @@ -126,7 +125,7 @@ simple - adapt as required for your distribution: 'pgadmin4-server.db' ) ``` - + This configuration allows easy switching between server and desktop modes for testing. @@ -137,13 +136,13 @@ simple - adapt as required for your distribution: ```bash (venv) $ python3 $PGADMIN4_SRC/web/setup.py ``` - + or by starting pgAdmin 4: ```bash (venv) $ python3 $PGADMIN4_SRC/web/pgAdmin4.py ``` - + Whilst it is possible to automatically run setup in desktop mode by running the runtime, that will not work in server mode as the runtime doesn't allow command line interaction with the setup program. @@ -228,7 +227,7 @@ To build a source tarball: (venv) $ make src ``` -To build a PIP Wheel, activate either a Python 3 virtual environment, configured +To build a PIP Wheel, activate either a Python 3 virtual environment, configured with all the required packages, and then run: ```bash @@ -266,7 +265,7 @@ See https://www.pgadmin.org/support/ for support options. If you would like to report a security issue with pgAdmin, please email **security (at) pgadmin (dot) org**. - + Note that this address should only be used for reporting security issues that you believe you've found in the design or code of pgAdmin, pgAgent, and the pgAdmin website. It should not be used to ask security questions. diff --git a/docs/en_US/code_overview.rst b/docs/en_US/code_overview.rst index a8c08bc7a..f89f873d8 100644 --- a/docs/en_US/code_overview.rst +++ b/docs/en_US/code_overview.rst @@ -5,7 +5,7 @@ ********************** The bulk of pgAdmin is a Python web application written using the Flask framework -on the backend, and HTML5 with CSS3, Bootstrap and jQuery on the front end. A +on the backend, and HTML5 with CSS3,ReactJS on the front end. A desktop runtime is also included for users that prefer a desktop application to a web application, which is written using NWjs (Node Webkit). diff --git a/docs/en_US/coding_standards.rst b/docs/en_US/coding_standards.rst index 648c9e5c3..2986c4539 100644 --- a/docs/en_US/coding_standards.rst +++ b/docs/en_US/coding_standards.rst @@ -64,7 +64,7 @@ All HTML must be HTML 5 compliant. Javascript ********** -Client-side code is written in Javascript using jQuery and various plugins. +Client-side code is written in Javascript using ReactJS and various plugins. Whilst much of the code is rendered from static files, there is also code that is rendered from templates using Jinja2 (often to inject the users settings) or constructed on the fly from module hooks. diff --git a/docs/en_US/menu_bar.rst b/docs/en_US/menu_bar.rst index 576d2fbc8..2f4b40592 100644 --- a/docs/en_US/menu_bar.rst +++ b/docs/en_US/menu_bar.rst @@ -25,9 +25,6 @@ Use the *File* menu to access the following options: +-------------------------+---------------------------------------------------------------------------------------------------------+ | *Reset Layout* | If you have modified the workspace, click to restore the default layout. | +-------------------------+---------------------------------------------------------------------------------------------------------+ -| *Lock Layout* | Click to open a submenu to select the level for locking the UI layout | -| | This can also be changed from browser display :ref:`preferences ` | -+-------------------------+---------------------------------------------------------------------------------------------------------+ | *Runtime* | Click to open a submenu to Configure, View Log and Zoom settings. Only visible when pgAdmin4 runs in | | | desktop mode. To know more about runtime menu :ref:`click here ` | +-------------------------+---------------------------------------------------------------------------------------------------------+ diff --git a/docs/en_US/preferences.rst b/docs/en_US/preferences.rst index aa7ed4c9b..5ce771849 100644 --- a/docs/en_US/preferences.rst +++ b/docs/en_US/preferences.rst @@ -46,19 +46,6 @@ Use the fields on the *Display* panel to specify general display preferences: * When the *Hide shared servers?* switch is set to *True*, the client will hide all the shared servers from the object explorer. -* Use the *Lock layout* field to lock the UI layout at different levels. This - can also be changed from File menu on the :ref:`menu bar ` - -+---------------------+-------------------------------------------------------------------+ -| Option | Action | -+=====================+===================================================================+ -| *None* | No locking. Every panel is resizable and dockable. | -+---------------------+-------------------------------------------------------------------+ -| *Prevent docking* | This will disable the docking/undocking of the panels | -+---------------------+-------------------------------------------------------------------+ -| *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 diff --git a/docs/en_US/theme/pgadmin4/static/style.css b/docs/en_US/theme/pgadmin4/static/style.css index ab87383b4..70bc7e9e6 100755 --- a/docs/en_US/theme/pgadmin4/static/style.css +++ b/docs/en_US/theme/pgadmin4/static/style.css @@ -2,7 +2,7 @@ html{ background-color: #fff; - + } body { @@ -10,6 +10,7 @@ body { font-family: Roboto, Helvetica Neue, -apple-system, BlinkMacSystemFont, Segoe UI, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; -webkit-font-smoothing: antialiased; background-color: #fff; + height: 100vh; } div.body { diff --git a/pkg/linux/build-functions.sh b/pkg/linux/build-functions.sh index e1546a143..7b19a560a 100644 --- a/pkg/linux/build-functions.sh +++ b/pkg/linux/build-functions.sh @@ -224,7 +224,7 @@ _copy_code() { cp "${SOURCEDIR}/pkg/linux/config_distro.py" "${SERVERROOT}/usr/${APP_NAME}/web/" cd "${SERVERROOT}/usr/${APP_NAME}/web/" || exit rm -f pgadmin4.db config_local.* - rm -rf karma.conf.js package.json node_modules/ regression/ tools/ pgadmin/static/js/generated/.cache + rm -rf jest.config.js babel.* package.json node_modules/ regression/ tools/ pgadmin/static/js/generated/.cache find . -name "tests" -type d -print0 | xargs -0 rm -rf find . -name "feature_tests" -type d -print0 | xargs -0 rm -rf find . -name "__pycache__" -type d -print0 | xargs -0 rm -rf diff --git a/pkg/mac/build-functions.sh b/pkg/mac/build-functions.sh index b49a93ce7..aed567df6 100644 --- a/pkg/mac/build-functions.sh +++ b/pkg/mac/build-functions.sh @@ -298,7 +298,7 @@ _complete_bundle() { cp -r "${SOURCE_DIR}/web" "${BUNDLE_DIR}/Contents/Resources/" cd "${BUNDLE_DIR}/Contents/Resources/web" || exit rm -f pgadmin4.db config_local.* - rm -rf karma.conf.js package.json .yarn* yarn* .editorconfig .eslint* node_modules/ regression/ tools/ pgadmin/static/js/generated/.cache + rm -rf jest.config.js babel.* package.json .yarn* yarn* .editorconfig .eslint* node_modules/ regression/ tools/ pgadmin/static/js/generated/.cache find . -name "tests" -type d -print0 | xargs -0 rm -rf find . -name "feature_tests" -type d -print0 | xargs -0 rm -rf find . -name "__pycache__" -type d -print0 | xargs -0 rm -rf diff --git a/runtime/.eslintrc.js b/runtime/.eslintrc.js index a7321716c..f228daa58 100644 --- a/runtime/.eslintrc.js +++ b/runtime/.eslintrc.js @@ -12,7 +12,6 @@ module.exports = { 'browser': true, 'es6': true, 'amd': true, - 'jasmine': true, }, 'extends': [ 'eslint:recommended', diff --git a/web/.eslintrc.js b/web/.eslintrc.js index 70c3bac9c..cd66bfdfb 100644 --- a/web/.eslintrc.js +++ b/web/.eslintrc.js @@ -12,7 +12,6 @@ module.exports = { 'browser': true, 'es6': true, 'amd': true, - 'jasmine': true, }, 'extends': [ 'eslint:recommended', @@ -41,10 +40,11 @@ module.exports = { 'plugins': [ 'react', '@babel', + 'jest' ], 'overrides': [ { - 'files': ['**/*.ts', '**/*.tsx'], + 'files': ['**/*.{ts,tsx}'], 'plugins': [ '@typescript-eslint', ], @@ -55,10 +55,20 @@ module.exports = { '@typescript-eslint/no-this-alias': ['off'], } }, + { + 'files': ['**/*{spec,test}.{js,jsx}', './regression/javascript/**/*.{js}'], + 'extends': ['eslint:recommended'], + 'env': { + 'jest': true + } + }, ], 'globals': { '_': true, 'module': true, + '__dirname': true, + 'global': true, + 'jest': true }, 'rules': { 'indent': [ diff --git a/web/babel.config.json b/web/babel.config.json new file mode 100644 index 000000000..81860237f --- /dev/null +++ b/web/babel.config.json @@ -0,0 +1,4 @@ +{ + "presets": [["@babel/preset-env", {"modules": "commonjs", "useBuiltIns": "usage", "corejs": 3}], "@babel/preset-react", "@babel/preset-typescript"], + "plugins": ["@babel/plugin-proposal-class-properties", "@babel/proposal-object-rest-spread", "@babel/plugin-transform-runtime"] +} diff --git a/web/jest.config.js b/web/jest.config.js new file mode 100644 index 000000000..06d03ec8f --- /dev/null +++ b/web/jest.config.js @@ -0,0 +1,57 @@ +const webpackShimAlias = require('./webpack.shim').resolveAlias; + +const webpackAliasToJestModules = ()=>{ + const ret = { + '\\.svg': '/regression/javascript/__mocks__/svg.js' + }; + Object.keys(webpackShimAlias).forEach((an)=>{ + // eg - sources: ./pgadmin/static/js/ to '^sources/(.*)$': '/pgadmin/static/js/$1' + let ap = webpackShimAlias[an].replace(__dirname, ''); + if(ap.endsWith('/')) { + ret[`^${an}/(.*)$`] = ap + '$1'; + return; + } + ret[`^${an}$`] = ap; + }); + + // Overrides + ret['^translations$'] = '/regression/javascript/fake_translations'; + ret['^pgadmin.browser.messages$'] = '/regression/javascript/fake_messages'; + ret['^pgadmin.browser.endpoints$'] = '/regression/javascript/fake_endpoints'; + ret['^pgadmin.browser.translations$'] = '/regression/javascript/fake_translations'; + ret['^pgadmin.user_management.current_user$'] = '/regression/javascript/fake_current_user'; + ret['^pgadmin.server.supported_servers$'] = '/regression/javascript/fake_supported_servers'; + + const sources = ret['^sources/(.*)$']; + delete ret['^sources/(.*)$']; + + ret['^sources/pgadmin$'] = '/regression/javascript/fake_pgadmin'; + ret['^sources/gettext$'] = '/regression/javascript/fake_gettext'; + ret['^sources/(.*)$'] = sources; + + // Only for tests + ret['^pgadmin.schema.dir/(.*)$'] = '/pgadmin/browser/server_groups/servers/databases/schemas/static/js/$1'; + ret['^browser/(.*)$'] = '/pgadmin/browser/static/js/$1'; + + return ret; +}; + +module.exports = { + 'roots': ['/pgadmin/', '/regression/javascript'], + 'moduleFileExtensions': ['js', 'jsx', 'ts', 'tsx'], + 'moduleNameMapper': webpackAliasToJestModules(), + 'transform': { + '^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': 'babel-jest', + }, + 'setupFilesAfterEnv': [ + '/regression/javascript/setup-jest.js', + ], + 'testMatch': [ + '/regression/javascript/**/*{spec,test}.{js,jsx,ts,tsx}' + ], + 'testEnvironment': 'jsdom', + 'transformIgnorePatterns': [ + '[/\\\\]node_modules[/\\\\](?!react-dnd|dnd-core|@react-dnd).+\\.(js|jsx|mjs|cjs|ts|tsx)$', + '^.+\\.module\\.(css|sass|scss)$' + ] +}; diff --git a/web/karma.conf.js b/web/karma.conf.js deleted file mode 100644 index 81c58c0f4..000000000 --- a/web/karma.conf.js +++ /dev/null @@ -1,106 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2023, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// - -// Karma configuration -const webpackConfig = require('./webpack.test.config.js'); -const isDocker = require('is-docker')(); -const webpack = require('webpack'); - -module.exports = function (config) { - config.set({ - frameworks: ['jasmine', 'source-map-support'], - reporters: ['progress', 'kjhtml'], - plugins: [ - 'karma-webpack', - 'karma-chrome-launcher', - 'karma-jasmine', - 'karma-jasmine-html-reporter', - 'karma-source-map-support', - 'karma-sourcemap-loader', - 'karma-coverage', - new webpack.SourceMapDevToolPlugin({ - /* - * filename: null, // if no value is provided the sourcemap is inlined - */ - filename: '[name].js.map', - test: /\.js$/i, // process .js files only - }), - ], - files: [ - {pattern: 'pgadmin/static/**/*.js', included: false, watched: true}, - {pattern: 'pgadmin/browser/static/js/**/*.js', included: false, watched: true}, - {pattern: 'regression/javascript/**/*.js', watched: true}, - ], - - // list of files to exclude - exclude: [ - 'pgadmin/static/vendor/**/*[Tt]est.js', - 'pgadmin/static/vendor/**/*[Ss]pec.js', - ], - - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: { - 'pgadmin/**/js/**/*.js?': ['sourcemap'], - 'regression/javascript/**/*.js': ['webpack', 'sourcemap'], - }, - - // optionally, configure the reporter - coverageReporter: { - reporters: [ - // reporters not supporting the `file` property - { type: 'html', subdir: 'report-html' }, - { type: 'lcovonly', subdir: 'report-lcov' }, - ], - dir : 'coverage/', - includeAllSources: true, - }, - - webpack: webpackConfig, - webpackMiddleware: { - stats: 'errors-only', - }, - - port: 9876, - - // enable / disable colors in the output (reporters and logs) - colors: true, - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_WARN, - - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: true, - usePolling: true, - - - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - customLaunchers: { - ChromeCustom: { - base: 'ChromeHeadless', - // We must disable the Chrome sandbox when running Chrome inside Docker (Chrome's sandbox needs - // more permissions than Docker allows by default) - flags: isDocker ? ['--no-sandbox'] : [], - }, - }, - browsers: ['ChromeCustom'], - - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: false, - - // Concurrency level - // how many browser should be started simultaneous - concurrency: Infinity, - }); -}; diff --git a/web/package.json b/web/package.json index 69dc35347..62bc57a3d 100644 --- a/web/package.json +++ b/web/package.json @@ -12,6 +12,7 @@ "@babel/eslint-plugin": "^7.17.7", "@babel/plugin-proposal-object-rest-spread": "^7.10.1", "@babel/plugin-syntax-jsx": "^7.16.0", + "@babel/plugin-transform-runtime": "^7.22.15", "@babel/preset-env": "^7.10.2", "@babel/preset-typescript": "^7.22.5", "@emotion/core": "^10.0.14", @@ -20,44 +21,35 @@ "@emotion/styled": "^11.11.0", "@emotion/utils": "^1.0.0", "@svgr/webpack": "^6.2.1", + "@testing-library/jest-dom": "^6.1.2", + "@testing-library/react": "12", + "@testing-library/user-event": "^14.4.3", + "@types/jest": "^29.5.4", "@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", "axios-mock-adapter": "^1.17.0", "babel-loader": "^8.1.0", "browserify": "^17.0.0", "buffer": "^6.0.3", "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": "^5.0.0", - "enzyme": "^3.11.0", "eslint": "^8.37.0", + "eslint-plugin-jest": "^27.4.0", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.3.0", "exports-loader": "^4.0.0", - "html-react-parser": "^4.2.0", + "html-react-parser": "^4.2.2", "image-minimizer-webpack-plugin": "^3.8.2", "imagemin": "^8.0.1", "imagemin-mozjpeg": "^10.0.0", "imagemin-optipng": "^8.0.0", "imports-loader": "^4.0.1", "is-docker": "^2.1.1", - "istanbul-instrumenter-loader": "^3.0.1", - "jasmine-core": "3.10.1", - "jasmine-enzyme": "^7.1.2", - "karma": "^6.3.15", - "karma-babel-preprocessor": "^8.0.0", - "karma-browserify": "^8.0.0", - "karma-chrome-launcher": "^3.1.0", - "karma-jasmine": "^4.0.1", - "karma-jasmine-html-reporter": "^1.4.0", - "karma-requirejs": "~1.1.0", - "karma-source-map-support": "^1.4.0", - "karma-sourcemap-loader": "^0.4.0", - "karma-webpack": "^5.0.0", + "jest": "^29.6.4", + "jest-environment-jsdom": "^29.6.4", "loader-utils": "^3.2.1", "mini-css-extract-plugin": "^2.7.6", "postcss-loader": "^7.1.0", @@ -87,6 +79,7 @@ "@date-io/core": "^1.3.6", "@date-io/date-fns": "1.x", "@emotion/sheet": "^1.0.1", + "@fortawesome/fontawesome-free": "latest", "@material-ui/core": "4.12.4", "@material-ui/icons": "^4.11.2", "@material-ui/lab": "4.0.0-alpha.61", @@ -103,7 +96,6 @@ "axios": "^1.4.0", "babelify": "~10.0.0", "bignumber.js": "^9.0.1", - "bootstrap": "^4.3.1", "brace": "^0.11.1", "browserfs": "^1.4.3", "chart.js": "^3.0.0", @@ -120,11 +112,8 @@ "immutability-helper": "^3.0.0", "insert-if": "^1.1.0", "ip-address": "^7.1.0", - "jquery": "^3.6.0", - "jquery-contextmenu": "^2.9.2", "json-bignumber": "^1.0.1", "jsoneditor": "^9.5.4", - "karma-coverage": "^2.0.3", "leaflet": "^1.5.1", "lodash": "4.*", "ml-matrix": "^6.5.0", @@ -150,10 +139,11 @@ "react-dom": "^17.0.1", "react-draggable": "^4.4.4", "react-dropzone": "^14.2.1", + "react-frame-component": "^5.2.6", "react-leaflet": "^3.2.2", + "react-new-window": "^1.0.1", "react-resize-detector": "^9.1.0", "react-rnd": "^10.3.5", - "react-router-dom": "^6.2.2", "react-select": "^5.7.2", "react-table": "^7.6.3", "react-timer-hook": "^3.0.5", @@ -163,16 +153,15 @@ "socket.io-client": "^4.5.0", "split.js": "^1.5.10", "styled-components": "^5.2.1", - "tempusdominus-core": "^5.19.3", "uplot": "^1.6.24", "uplot-react": "^1.1.4", "valid-filename": "^2.0.1", - "webcabin-docker": "https://github.com/pgadmin-org/wcdocker#460fc6d90ba170bb177faaa8277f5fbb8279522a", "wkx": "^0.5.0", "xterm": "^4.11.0", "xterm-addon-fit": "^0.5.0", "xterm-addon-search": "^0.8.0", - "xterm-addon-web-links": "^0.4.0" + "xterm-addon-web-links": "^0.4.0", + "zustand": "^4.4.1" }, "scripts": { "linter": "yarn eslint --no-eslintrc -c .eslintrc.js --ext .js --ext .jsx --ext .ts --ext .tsx .", @@ -181,12 +170,12 @@ "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=3072 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", + "bundle": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=2048 yarn run bundle:dev", + "test:js-once": "yarn run linter && yarn run jest --maxWorkers=50%", + "test:js": "yarn run test:js-once --watch", + "test:js-coverage": "yarn run test:js-once --collect-coverage", "test:feature": "yarn run bundle && python regression/runtests.py --pkg feature_tests", - "test": "yarn run test:karma-once && yarn run bundle && python regression/runtests.py", + "test": "yarn run test:js-once && yarn run bundle && python regression/runtests.py", "pep8": "pycodestyle --config=../.pycodestyle ../docs && pycodestyle --config=../.pycodestyle ../pkg && pycodestyle --config=../.pycodestyle ../tools && pycodestyle --config=../.pycodestyle ../web", "auditjs-html": "yarn audit --json | yarn run yarn-audit-html --output ../auditjs.html", "auditjs": "yarn audit --groups dependencies", diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py index 14b319a1b..fc402b8d9 100644 --- a/web/pgadmin/__init__.py +++ b/web/pgadmin/__init__.py @@ -165,13 +165,6 @@ class PgAdmin(Flask): return scripts - @property - def panels(self): - panels = [] - for module in self.submodules: - panels.extend(module.get_panels()) - return panels - @property def menu_items(self): from operator import attrgetter diff --git a/web/pgadmin/about/static/js/AboutComponent.jsx b/web/pgadmin/about/static/js/AboutComponent.jsx index cd34002e1..f975f4845 100644 --- a/web/pgadmin/about/static/js/AboutComponent.jsx +++ b/web/pgadmin/about/static/js/AboutComponent.jsx @@ -17,8 +17,8 @@ import { makeStyles } from '@material-ui/styles'; import { InputText } from '../../../static/js/components/FormComponents'; import getApiInstance from '../../../static/js/api_instance'; import { copyToClipboard } from '../../../static/js/clipboard'; -import Notify from '../../../static/js/helpers/Notifier'; import { useDelayedCaller } from '../../../static/js/custom_hooks'; +import { usePgAdmin } from '../../../static/js/BrowserComponent'; const useStyles = makeStyles((theme)=>({ @@ -44,6 +44,7 @@ export default function AboutComponent() { const revertCopiedText = useDelayedCaller(()=>{ setCopyText(gettext('Copy')); }); + const pgAdmin = usePgAdmin(); useEffect(() => { const about_url = url_for('about.index'); @@ -52,7 +53,7 @@ export default function AboutComponent() { api.get(about_url).then((res)=>{ setAboutData(res.data.data); }).catch((err)=>{ - Notify.error(err); + pgAdmin.Browser.notifier.error(err); }); }, []); diff --git a/web/pgadmin/about/static/js/about.js b/web/pgadmin/about/static/js/about.js index 007dfae96..f24110f34 100644 --- a/web/pgadmin/about/static/js/about.js +++ b/web/pgadmin/about/static/js/about.js @@ -9,7 +9,6 @@ import React from 'react'; import gettext from 'sources/gettext'; -import Notify from '../../../static/js/helpers/Notifier'; import pgAdmin from 'sources/pgadmin'; import AboutComponent from './AboutComponent'; import current_user from 'pgadmin.user_management.current_user'; @@ -41,9 +40,9 @@ class About { } // Render About component - Notify.showModal(gettext('About %s', pgAdmin.Browser.utils.app_name), () => { + pgAdmin.Browser.notifier.showModal(gettext('About %s', pgAdmin.Browser.utils.app_name), () => { return ; - }, { isFullScreen: false, isResizeable: true, showFullScreen: true, + }, { isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true, dialogWidth: dlgWidth, dialogHeight: dlgHeight, minHeight: dlgHeight }); } @@ -53,4 +52,4 @@ pgAdmin.About = About.getInstance(); module.exports = { About: About, -}; \ No newline at end of file +}; diff --git a/web/pgadmin/authenticate/static/js/kerberos.js b/web/pgadmin/authenticate/static/js/kerberos.js index 102d6999a..03a00f33b 100644 --- a/web/pgadmin/authenticate/static/js/kerberos.js +++ b/web/pgadmin/authenticate/static/js/kerberos.js @@ -9,7 +9,7 @@ import url_for from 'sources/url_for'; import userInfo from 'pgadmin.user_management.current_user'; -import pgConst from 'pgadmin.browser.constants'; +import {AUTH_METHODS} from 'pgadmin.browser.constants'; function fetch_ticket() { // Fetch the Kerberos Updated ticket through SPNEGO @@ -52,7 +52,7 @@ function fetch_ticket_lifetime () { function validate_kerberos_ticket() { // Ping pgAdmin server every 10 seconds // to fetch the Kerberos ticket lifetime left - if (userInfo['current_auth_source'] != pgConst['KERBEROS']) return; + if (userInfo['current_auth_source'] != AUTH_METHODS['KERBEROS']) return; return setInterval(function() { let newPromise = fetch_ticket_lifetime(); diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py index 36f24990d..c6dd36a00 100644 --- a/web/pgadmin/browser/__init__.py +++ b/web/pgadmin/browser/__init__.py @@ -88,61 +88,6 @@ PASS_ERROR = gettext('Error: {error}\n {pass_error}').format( class BrowserModule(PgAdminModule): LABEL = gettext('Browser') - def get_own_stylesheets(self): - stylesheets = [] - context_menu_file = 'vendor/jQuery-contextMenu/' \ - 'jquery.contextMenu.min.css' - wcdocker_file = 'vendor/wcDocker/wcDocker.min.css' - if current_app.debug: - context_menu_file = 'vendor/jQuery-contextMenu/' \ - 'jquery.contextMenu.css' - wcdocker_file = 'vendor/wcDocker/wcDocker.css' - # Add browser stylesheets - for (endpoint, filename) in [ - ('static', 'vendor/codemirror/codemirror.css'), - ('static', 'vendor/codemirror/addon/dialog/dialog.css'), - ('static', context_menu_file), - ('static', wcdocker_file) - ]: - stylesheets.append(url_for(endpoint, filename=filename)) - return stylesheets - - def get_own_menuitems(self): - menus = { - 'file_items': [ - MenuItem( - name='mnu_locklayout', - module=PGADMIN_BROWSER, - label=gettext('Lock Layout'), - priority=999, - menu_items=[MenuItem( - name='mnu_lock_none', - module=PGADMIN_BROWSER, - callback='mnu_lock_none', - priority=0, - label=gettext('None'), - checked=True - ), MenuItem( - name='mnu_lock_docking', - module=PGADMIN_BROWSER, - callback='mnu_lock_docking', - priority=1, - label=gettext('Prevent Docking'), - checked=False - ), MenuItem( - name='mnu_lock_full', - module=PGADMIN_BROWSER, - callback='mnu_lock_full', - priority=2, - label=gettext('Full Lock'), - checked=False - )] - ) - ] - } - - return menus - def register_preferences(self): register_browser_preferences(self) @@ -156,7 +101,6 @@ class BrowserModule(PgAdminModule): 'browser.check_master_password', 'browser.set_master_password', 'browser.reset_master_password', - 'browser.lock_layout', ] def register(self, app, options): @@ -416,47 +360,6 @@ def _get_supported_browser(): return browser_name, browser_known, version -def check_browser_upgrade(): - """ - This function is used to check the browser version. - :return: - """ - data = None - url = '%s?version=%s' % (config.UPGRADE_CHECK_URL, config.APP_VERSION) - current_app.logger.debug('Checking version data at: %s' % url) - - try: - # Do not wait for more than 5 seconds. - # It stuck on rendering the browser.html, while working in the - # broken network. - if os.path.exists(config.CA_FILE): - response = urlopen(url, data, 5, cafile=config.CA_FILE) - else: - response = urlopen(url, data, 5) - current_app.logger.debug( - 'Version check HTTP response code: %d' % response.getcode() - ) - - if response.getcode() == 200: - data = json.loads(response.read().decode('utf-8')) - current_app.logger.debug('Response data: %s' % data) - except Exception: - current_app.logger.exception('Exception when checking for update') - - if data is not None and \ - data[config.UPGRADE_CHECK_KEY]['version_int'] > \ - config.APP_VERSION_INT: - msg = render_template( - MODULE_NAME + "/upgrade.html", - current_version=config.APP_VERSION, - upgrade_version=data[config.UPGRADE_CHECK_KEY]['version'], - product_name=config.APP_NAME, - download_url=data[config.UPGRADE_CHECK_KEY]['download_url'] - ) - - flash(msg, MessageType.WARNING) - - @blueprint.route("/") @pgCSRFProtect.exempt @login_required @@ -491,15 +394,6 @@ def index(): flash(msg, MessageType.WARNING) - # Get the current version info from the website, and flash a message if - # the user is out of date, and the check is enabled. - if config.UPGRADE_CHECK_ENABLED: - last_check = get_setting('LastUpdateCheck', default='0') - today = time.strftime('%Y%m%d') - if int(last_check) < int(today): - check_browser_upgrade() - store_setting('LastUpdateCheck', today) - session['allow_save_password'] = True if config.SERVER_MODE and not config.MASTER_PASSWORD_REQUIRED and \ @@ -605,7 +499,6 @@ def utils(): editor_indent_with_tabs = False if editor_use_spaces else True prefs = Preferences.module('browser') - current_ui_lock = prefs.preference('lock_layout').get() # Try to fetch current libpq version from the driver try: from config import PG_DEFAULT_DRIVER @@ -672,7 +565,6 @@ def utils(): auth_source=auth_source, heartbeat_timeout=config.SERVER_HEARTBEAT_TIMEOUT, password_length_min=config.PASSWORD_LENGTH_MIN, - current_ui_lock=current_ui_lock, shared_storage_list=shared_storage_list, restricted_shared_storage_list=[] if current_user.has_role( "Administrator") else restricted_shared_storage_list, @@ -689,19 +581,6 @@ def exposed_urls(): ) -@blueprint.route("/js/constants.js") -@pgCSRFProtect.exempt -def app_constants(): - return make_response( - render_template('browser/js/constants.js', - INTERNAL=INTERNAL, - LDAP=LDAP, - KERBEROS=KERBEROS, - OAUTH2=OAUTH2), - 200, {'Content-Type': MIMETYPE_APP_JS} - ) - - @blueprint.route("/js/error.js") @pgCSRFProtect.exempt @login_required @@ -1033,21 +912,6 @@ def set_master_password(): ) -@blueprint.route("/lock_layout", endpoint="lock_layout", methods=["PUT"]) -def lock_layout(): - data = None - - if hasattr(request.data, 'decode'): - data = request.data.decode('utf-8') - - if data != '': - data = json.loads(data) - - blueprint.lock_layout.set(data['value']) - - return make_json_response() - - # Only register route if SECURITY_CHANGEABLE is set to True # We can't access app context here so cannot # use app.config['SECURITY_CHANGEABLE'] diff --git a/web/pgadmin/browser/register_browser_preferences.py b/web/pgadmin/browser/register_browser_preferences.py index 331c6e5af..faa605474 100644 --- a/web/pgadmin/browser/register_browser_preferences.py +++ b/web/pgadmin/browser/register_browser_preferences.py @@ -15,12 +15,6 @@ from pgadmin.utils.constants import PREF_LABEL_DISPLAY,\ from flask import current_app import config -LOCK_LAYOUT_LEVEL = { - 'PREVENT_DOCKING': 'docking', - 'FULL': 'full', - 'NONE': 'none' -} - def register_browser_preferences(self): self.show_system_objects = self.preference.register( @@ -97,21 +91,6 @@ def register_browser_preferences(self): ) ) - self.lock_layout = self.preference.register( - 'display', 'lock_layout', - gettext('Lock Layout'), 'radioModern', LOCK_LAYOUT_LEVEL['NONE'], - category_label=PREF_LABEL_DISPLAY, options=[ - {'label': gettext('None'), 'value': LOCK_LAYOUT_LEVEL['NONE']}, - {'label': gettext('Prevent Docking'), - 'value': LOCK_LAYOUT_LEVEL['PREVENT_DOCKING']}, - {'label': gettext('Full Lock'), - 'value': LOCK_LAYOUT_LEVEL['FULL']}, - ], - help_str=gettext( - 'Lock the UI layout at different levels' - ) - ) - self.table_row_count_threshold = self.preference.register( 'properties', 'table_row_count_threshold', gettext("Count rows if estimated less than"), 'integer', 2000, diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/utils.py index d563820c5..a2e8de560 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/utils.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/utils.py @@ -370,9 +370,6 @@ def convert_length_precision_to_string(data): :return: """ - # We need to handle the below case because jquery has changed - # undefined/null values to empty strings - # https://github.com/jquery/jquery/commit/36d2d9ae937f626d98319ed850905e8d1cbfd078 if 'attlen' in data and data['attlen'] == '': data['attlen'] = None elif 'attlen' in data and data['attlen'] is not None: diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/compound_triggers/static/js/compound_trigger.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/compound_triggers/static/js/compound_trigger.js index f69c0cb92..4be7005a1 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/compound_triggers/static/js/compound_trigger.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/compound_triggers/static/js/compound_trigger.js @@ -9,7 +9,6 @@ import { getNodeListByName } from '../../../../../../../../static/js/node_ajax'; import CompoundTriggerSchema from './compound_trigger.ui'; -import Notify from '../../../../../../../../../static/js/helpers/Notifier'; import getApiInstance from '../../../../../../../../../static/js/api_instance'; define('pgadmin.node.compound_trigger', [ @@ -118,14 +117,14 @@ define('pgadmin.node.compound_trigger', [ {'is_enable_trigger' : 'O'} ).then(({data: res})=> { if(res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.removeIcon(i); data.icon = 'icon-compound_trigger'; t.addIcon(i, {icon: data.icon}); t.updateAndReselectNode(i, data); } }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.refresh(i); }); }, @@ -146,14 +145,14 @@ define('pgadmin.node.compound_trigger', [ {'is_enable_trigger' : 'D'} ).then(({data: res})=> { if(res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.removeIcon(i); data.icon = 'icon-compound_trigger-bad'; t.addIcon(i, {icon: data.icon}); t.updateAndReselectNode(i, data); } }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.refresh(i); }); }, diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/js/check_constraint.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/js/check_constraint.js index f73041c33..fb3362ac0 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/js/check_constraint.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/js/check_constraint.js @@ -8,7 +8,6 @@ ////////////////////////////////////////////////////////////// import CheckConstraintSchema from './check_constraint.ui'; -import Notify from '../../../../../../../../../../static/js/helpers/Notifier'; import _ from 'lodash'; import getApiInstance from '../../../../../../../../../../static/js/api_instance'; @@ -73,7 +72,7 @@ define('pgadmin.node.check_constraint', [ getApiInstance().get(obj.generate_url(i, 'validate', d, true)) .then(({data: res})=>{ if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.removeIcon(i); data.valid = true; data.icon = 'icon-check_constraint'; @@ -83,7 +82,7 @@ define('pgadmin.node.check_constraint', [ } }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.unload(i); }); } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/static/js/exclusion_constraint.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/static/js/exclusion_constraint.ui.js index 0edbaf0ff..cb070b800 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/static/js/exclusion_constraint.ui.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/static/js/exclusion_constraint.ui.js @@ -14,7 +14,7 @@ import { SCHEMA_STATE_ACTIONS } from '../../../../../../../../../../static/js/Sc import DataGridViewWithHeaderForm from '../../../../../../../../../../static/js/helpers/DataGridViewWithHeaderForm'; import { getNodeAjaxOptions, getNodeListByName } from '../../../../../../../../../static/js/node_ajax'; import TableSchema from '../../../../static/js/table.ui'; -import Notify from '../../../../../../../../../../static/js/helpers/Notifier'; +import pgAdmin from 'sources/pgadmin'; function getData(data) { let res = []; @@ -275,7 +275,7 @@ export default class ExclusionConstraintSchema extends BaseUISchema { options: this.fieldOptions.amname, deferredDepChange: (state, source, topState, actionObj)=>{ return new Promise((resolve)=>{ - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Change access method?'), gettext('Changing access method will clear columns collection'), function () { diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.js index 6715739ec..e8d609df7 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.js @@ -8,7 +8,6 @@ ////////////////////////////////////////////////////////////// import { getNodeForeignKeySchema } from './foreign_key.ui'; -import Notify from '../../../../../../../../../../static/js/helpers/Notifier'; import _ from 'lodash'; import getApiInstance from '../../../../../../../../../../static/js/api_instance'; @@ -69,7 +68,7 @@ define('pgadmin.node.foreign_key', [ getApiInstance().get(obj.generate_url(i, 'validate', d, true)) .then(({data: res})=>{ if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.removeIcon(i); data.valid = true; data.icon = 'icon-foreign_key'; @@ -79,7 +78,7 @@ define('pgadmin.node.foreign_key', [ } }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.unload(i); }); } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/js/index.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/js/index.ui.js index 464369d27..dffc88494 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/js/index.ui.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/js/index.ui.js @@ -12,7 +12,7 @@ import BaseUISchema from 'sources/SchemaView/base_schema.ui'; import DataGridViewWithHeaderForm from '../../../../../../../../../static/js/helpers/DataGridViewWithHeaderForm'; import _ from 'lodash'; import { isEmptyString } from 'sources/validators'; -import Notify from '../../../../../../../../../static/js/helpers/Notifier'; +import pgAdmin from 'sources/pgadmin'; function inSchema(node_info) { @@ -476,7 +476,7 @@ export default class IndexSchema extends BaseUISchema { }; if((state.amname != actionObj?.oldState.amname) && state.columns?.length > 0) { return new Promise((resolve)=>{ - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Warning'), gettext('Changing access method will clear columns collection. Do you want to continue?'), function () { diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.js index c075a90ee..24f7ffb88 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.js @@ -8,18 +8,17 @@ ////////////////////////////////////////////////////////////// import { getNodePartitionTableSchema } from './partition.ui'; -import Notify from '../../../../../../../../../static/js/helpers/Notifier'; import _ from 'lodash'; import getApiInstance from '../../../../../../../../../static/js/api_instance'; define([ - 'sources/gettext', 'sources/url_for', 'jquery', + 'sources/gettext', 'sources/url_for', 'sources/pgadmin', 'pgadmin.browser', 'pgadmin.node.schema.dir/schema_child_tree_node', 'sources/utils', 'pgadmin.browser.collection', ], function( - gettext, url_for, $, pgAdmin, pgBrowser, + gettext, url_for, pgAdmin, pgBrowser, SchemaChildTreeNode, pgadminUtils ) { @@ -151,7 +150,7 @@ function( }, on_done: function(res, data, t, i) { if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.removeIcon(i); data.icon = 'icon-partition'; t.addIcon(i, {icon: data.icon}); @@ -186,12 +185,12 @@ function( getApiInstance().put(obj.generate_url(i, 'set_trigger' , d, true), params) .then(({data: res})=>{ if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.updateAndReselectNode(i, d); } }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.refresh(i); }); }, @@ -215,7 +214,7 @@ function( if (!d) return false; - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Truncate Table'), gettext('Are you sure you want to truncate table %s?', d.label), function () { @@ -225,7 +224,7 @@ function( obj.on_done(res, data, t, i); }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.unload(i); }); }, @@ -241,7 +240,7 @@ function( if (!d) return false; - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Reset statistics'), gettext('Are you sure you want to reset the statistics for table "%s"?', d._label), function () { @@ -251,7 +250,7 @@ function( obj.on_done(res, data, t, i); }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.unload(i); }); }, @@ -276,14 +275,14 @@ function( title = gettext('Detach Partition Finalize'); } - Notify.confirm( + pgAdmin.Browser.notifier.confirm( title, gettext('Are you sure you want to detach the partition %s?', d._label), function () { getApiInstance().put(obj.generate_url(i, 'detach' , d, true), params) .then(({data: res})=>{ if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); let n = t.next(i); if (!n) { n = t.prev(i); @@ -298,7 +297,7 @@ function( } }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); }); }, function() {/*This is intentional (SonarQube)*/} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/static/js/rule.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/static/js/rule.js index c60a6ddb7..e6d9599a1 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/static/js/rule.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/static/js/rule.js @@ -7,15 +7,14 @@ // ////////////////////////////////////////////////////////////// import RuleSchema from './rule.ui'; -import Notify from '../../../../../../../../../static/js/helpers/Notifier'; import _ from 'lodash'; import getApiInstance from '../../../../../../../../../static/js/api_instance'; define('pgadmin.node.rule', [ - 'sources/gettext', 'sources/url_for', 'jquery', + 'sources/gettext', 'sources/url_for', 'sources/pgadmin', 'pgadmin.browser', 'pgadmin.node.schema.dir/schema_child_tree_node', -], function(gettext, url_for, $, pgAdmin, pgBrowser, SchemaChildTreeNode) { +], function(gettext, url_for, pgAdmin, pgBrowser, SchemaChildTreeNode) { /** Create and add a rule collection into nodes @@ -137,14 +136,14 @@ define('pgadmin.node.rule', [ let data = d; getApiInstance().put(obj.generate_url(i, 'obj' , d, true), {'is_enable_rule' : 'O'}) .then(()=>{ - Notify.success('Rule updated.'); + pgAdmin.Browser.notifier.success('Rule updated.'); t.removeIcon(i); data.icon = 'icon-rule'; t.addIcon(i, {icon: data.icon}); t.updateAndReselectNode(i, data); }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.refresh(i); }); }, @@ -162,14 +161,14 @@ define('pgadmin.node.rule', [ let data = d; getApiInstance().put(obj.generate_url(i, 'obj' , d, true), {'is_enable_rule' : 'D'}) .then(()=>{ - Notify.success('Rule updated'); + pgAdmin.Browser.notifier.success('Rule updated'); t.removeIcon(i); data.icon = 'icon-rule-bad'; t.addIcon(i, {icon: data.icon}); t.updateAndReselectNode(i, data); }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.refresh(i); }); }, diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/enable_disable_triggers.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/enable_disable_triggers.js index aee8cab75..a247f28c2 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/enable_disable_triggers.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/enable_disable_triggers.js @@ -8,15 +8,16 @@ ////////////////////////////////////////////////////////////// import axios from 'axios'; +import pgAdmin from 'sources/pgadmin'; -export function disableTriggers(tree, Notify, generateUrl, args) { - return setTriggers(tree, Notify, generateUrl, args, {is_enable_trigger: 'D' }); +export function disableTriggers(tree, generateUrl, args) { + return setTriggers(tree, generateUrl, args, {is_enable_trigger: 'D' }); } -export function enableTriggers(tree, Notify, generateUrl, args) { - return setTriggers(tree, Notify, generateUrl, args, {is_enable_trigger: 'O' }); +export function enableTriggers(tree, generateUrl, args) { + return setTriggers(tree, generateUrl, args, {is_enable_trigger: 'O' }); } -function setTriggers(tree, Notify, generateUrl, args, params) { +function setTriggers(tree, generateUrl, args, params) { const treeNode = retrieveTreeNode(args, tree); if (!treeNode || treeNode.getData() === null || treeNode.getData() === undefined) @@ -28,7 +29,7 @@ function setTriggers(tree, Notify, generateUrl, args, params) { ) .then((res) => { if (res.data.success === 1) { - Notify.success(res.data.info); + pgAdmin.Browser.notifier.success(res.data.info); treeNode.data.has_enable_triggers = res.data.data.has_enable_triggers; treeNode.reload(tree); @@ -38,7 +39,7 @@ function setTriggers(tree, Notify, generateUrl, args, params) { try { const err = xhr.response.data; if (err.success === 0) { - Notify.error(err.errormsg); + pgAdmin.Browser.notifier.error(err.errormsg); } } catch (e) { console.warn(e.stack || e); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js index 030989c8f..f25cbd685 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js @@ -7,20 +7,19 @@ ////////////////////////////////////////////////////////////// import { getNodeTableSchema } from './table.ui'; -import Notify from '../../../../../../../../static/js/helpers/Notifier'; import _ from 'lodash'; import getApiInstance from '../../../../../../../../static/js/api_instance'; define('pgadmin.node.table', [ 'pgadmin.tables.js/enable_disable_triggers', - 'sources/gettext', 'sources/url_for', 'jquery', + 'sources/gettext', 'sources/url_for', 'sources/pgadmin', 'pgadmin.browser', 'pgadmin.node.schema.dir/child','pgadmin.node.schema.dir/schema_child_tree_node', 'pgadmin.browser.collection', 'pgadmin.node.column', 'pgadmin.node.constraints', ], function( tableFunctions, - gettext, url_for, $, pgAdmin, pgBrowser, SchemaChild, SchemaChildTreeNode + gettext, url_for, pgAdmin, pgBrowser, SchemaChild, SchemaChildTreeNode ) { if (!pgBrowser.Nodes['coll-table']) { @@ -145,7 +144,6 @@ define('pgadmin.node.table', [ enable_triggers_on_table: function(args) { tableFunctions.enableTriggers( pgBrowser.tree, - Notify, this.generate_url.bind(this), args ); @@ -154,7 +152,6 @@ define('pgadmin.node.table', [ disable_triggers_on_table: function(args) { tableFunctions.disableTriggers( pgBrowser.tree, - Notify, this.generate_url.bind(this), args ); @@ -183,7 +180,7 @@ define('pgadmin.node.table', [ if (!d) return false; - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Truncate Table'), gettext('Are you sure you want to truncate table %s?', d.label), function () { @@ -191,18 +188,18 @@ define('pgadmin.node.table', [ getApiInstance().put(obj.generate_url(i, 'truncate' , d, true), params) .then(({data: res})=>{ if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.removeIcon(i); data.icon = data.is_partitioned ? 'icon-partition': 'icon-table'; t.addIcon(i, {icon: data.icon}); t.updateAndReselectNode(i, data); } if (res.success == 2) { - Notify.error(res.info); + pgAdmin.Browser.notifier.error(res.info); } }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.refresh(i); }); }, function() {/*This is intentional (SonarQube)*/} @@ -218,7 +215,7 @@ define('pgadmin.node.table', [ if (!d) return false; - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Reset statistics'), gettext('Are you sure you want to reset the statistics for table "%s"?', d._label), function () { @@ -226,7 +223,7 @@ define('pgadmin.node.table', [ getApiInstance().delete(obj.generate_url(i, 'reset' , d, true)) .then(({data: res})=>{ if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.removeIcon(i); data.icon = data.is_partitioned ? 'icon-partition': 'icon-table'; t.addIcon(i, {icon: data.icon}); @@ -234,7 +231,7 @@ define('pgadmin.node.table', [ } }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.refresh(i); }); }, @@ -257,12 +254,12 @@ define('pgadmin.node.table', [ // Fetch the total rows of a table getApiInstance().get(obj.generate_url(i, 'count_rows' , newD, true)) .then(({data: res})=>{ - Notify.success(res.info, null); + pgAdmin.Browser.notifier.success(res.info, null); d.rows_cnt = res.data.total_rows; t.updateAndReselectNode(i, d); }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.refresh(i); }); }, diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js index bab9d5050..7a1b0672c 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js @@ -22,7 +22,7 @@ import { getNodeVacuumSettingsSchema } from '../../../../../static/js/vacuum.ui' import { getNodeForeignKeySchema } from '../../constraints/foreign_key/static/js/foreign_key.ui'; import { getNodeExclusionConstraintSchema } from '../../constraints/exclusion_constraint/static/js/exclusion_constraint.ui'; import { getNodePrivilegeRoleSchema } from '../../../../../static/js/privilege.ui'; -import Notify from '../../../../../../../../static/js/helpers/Notifier'; +import pgAdmin from 'sources/pgadmin'; export function getNodeTableSchema(treeNodeInfo, itemNodeData, pgBrowser) { const spcname = ()=>getNodeListByName('tablespace', treeNodeInfo, itemNodeData, {}, (m)=>{ @@ -622,7 +622,7 @@ export default class TableSchema extends BaseUISchema { group: 'advanced', min_version: 90600, depChange: (state)=>{ if (state.rlspolicy && this.origData.rlspolicy != state.rlspolicy) { - Notify.alert( + pgAdmin.Browser.notifier.alert( gettext('Check Policy?'), gettext('Please check if any policy exists. If no policy exists for the table, a default-deny policy is used, meaning that no rows are visible or can be modified by other users') ); @@ -752,7 +752,7 @@ export default class TableSchema extends BaseUISchema { }; if(!isEmptyString(state.typname) && isEmptyString(actionObj.oldState.typname)) { return new Promise((resolve)=>{ - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Remove column definitions?'), gettext('Changing \'Of type\' will remove column definitions.'), function () { diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js index 09d028a55..c83b06fdd 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js @@ -8,17 +8,16 @@ ////////////////////////////////////////////////////////////// import { getNodeListByName, getNodeAjaxOptions } from '../../../../../../../../static/js/node_ajax'; import TriggerSchema from './trigger.ui'; -import Notify from '../../../../../../../../../static/js/helpers/Notifier'; import _ from 'lodash'; import getApiInstance from '../../../../../../../../../static/js/api_instance'; define('pgadmin.node.trigger', [ - 'sources/gettext', 'sources/url_for', 'jquery', + 'sources/gettext', 'sources/url_for', 'sources/pgadmin', 'pgadmin.browser', 'pgadmin.node.schema.dir/schema_child_tree_node', 'pgadmin.browser.collection', ], function( - gettext, url_for, $, pgAdmin, pgBrowser, SchemaChildTreeNode + gettext, url_for, pgAdmin, pgBrowser, SchemaChildTreeNode ) { if (!pgBrowser.Nodes['coll-trigger']) { @@ -118,7 +117,7 @@ define('pgadmin.node.trigger', [ getApiInstance().put(obj.generate_url(i, 'enable' , d, true), {'is_enable_trigger' : 'O'}) .then(({data: res})=>{ if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.removeIcon(i); data.icon = 'icon-trigger'; data.has_enable_triggers = res.data.has_enable_triggers; @@ -127,7 +126,7 @@ define('pgadmin.node.trigger', [ } }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.refresh(i); }); }, @@ -146,7 +145,7 @@ define('pgadmin.node.trigger', [ getApiInstance().put(obj.generate_url(i, 'enable' , d, true), {'is_enable_trigger' : 'D'}) .then(({data: res})=>{ if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.removeIcon(i); data.icon = 'icon-trigger-bad'; data.has_enable_triggers = res.data.has_enable_triggers; @@ -155,7 +154,7 @@ define('pgadmin.node.trigger', [ } }) .catch((error)=>{ - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.refresh(i); }); }, diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js index 9f315227d..583f22d98 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js @@ -11,17 +11,16 @@ import MViewSchema from './mview.ui'; import { getNodeListByName, getNodeAjaxOptions } from '../../../../../../../static/js/node_ajax'; import { getNodePrivilegeRoleSchema } from '../../../../../static/js/privilege.ui'; import { getNodeVacuumSettingsSchema } from '../../../../../static/js/vacuum.ui'; -import Notify from '../../../../../../../../static/js/helpers/Notifier'; import _ from 'lodash'; import getApiInstance from '../../../../../../../../static/js/api_instance'; define('pgadmin.node.mview', [ - 'sources/gettext', 'sources/url_for', 'jquery', + 'sources/gettext', 'sources/url_for', 'sources/pgadmin', 'pgadmin.browser', 'pgadmin.node.schema.dir/child', 'pgadmin.node.schema.dir/schema_child_tree_node', 'sources/utils', ], function( - gettext, url_for, $, pgAdmin, pgBrowser, + gettext, url_for, pgAdmin, pgBrowser, schemaChild, schemaChildTreeNode, commonUtils ) { @@ -176,7 +175,7 @@ define('pgadmin.node.mview', [ if (pgBrowser.tree.hasParent(j)) { j = pgBrowser.tree.parent(j); } else { - Notify.alert(gettext('Please select server or child node from tree.')); + pgAdmin.Browser.notifier.alert(gettext('Please select server or child node from tree.')); break; } } @@ -193,7 +192,7 @@ define('pgadmin.node.mview', [ api.get(obj.generate_url(i, 'check_utility_exists' , d, true)) .then(({data: res})=>{ if (!res.success) { - Notify.alert( + pgAdmin.Browser.notifier.alert( gettext('Utility not found'), res.errormsg ); @@ -206,20 +205,20 @@ define('pgadmin.node.mview', [ //Do nothing as we are creating the job and exiting from the main dialog pgBrowser.BgProcessManager.startProcess(refreshed_res.data.job_id, refreshed_res.data.desc); } else { - Notify.alert( + pgAdmin.Browser.notifier.alert( gettext('Failed to create materialized view refresh job.'), refreshed_res.errormsg ); } }) .catch((error)=>{ - Notify.pgRespErrorNotify( + pgAdmin.Browser.notifier.pgRespErrorNotify( error, gettext('Failed to create materialized view refresh job.') ); }); }) .catch(()=>{ - Notify.alert( + pgAdmin.Browser.notifier.alert( gettext('Utility not found'), gettext('Failed to fetch Utility information') ); diff --git a/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js b/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js index 19eb6b434..8419aaf0a 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js +++ b/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js @@ -11,16 +11,15 @@ import { getNodeAjaxOptions, getNodeListByName } from '../../../../../static/js/ import { getNodePrivilegeRoleSchema } from '../../../static/js/privilege.ui'; import { getNodeVariableSchema } from '../../../static/js/variable.ui'; import DatabaseSchema from './database.ui'; -import Notify from '../../../../../../static/js/helpers/Notifier'; import { showServerPassword } from '../../../../../../static/js/Dialogs/index'; import _ from 'lodash'; import getApiInstance, { parseApiError } from '../../../../../../static/js/api_instance'; define('pgadmin.node.database', [ - 'sources/gettext', 'sources/url_for', 'jquery', + 'sources/gettext', 'sources/url_for', 'sources/pgadmin', 'pgadmin.browser.utils', 'pgadmin.authenticate.kerberos', 'pgadmin.browser.collection', -], function(gettext, url_for, $, pgAdmin, pgBrowser, Kerberos) { +], function(gettext, url_for, pgAdmin, pgBrowser, Kerberos) { function canDeleteWithForce(itemNodeData, item) { let treeData = pgBrowser.tree.getTreeNodeHierarchy(item), @@ -189,7 +188,7 @@ define('pgadmin.node.database', [ connect(self, d, t, i, true); return; } - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Connection lost'), gettext('Would you like to reconnect to the database?'), function() { @@ -231,7 +230,7 @@ define('pgadmin.node.database', [ d = i ? t.itemData(i) : undefined; if (d) { - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Disconnect from database'), gettext('Are you sure you want to disconnect from database - %s?', d.label), function() { @@ -244,7 +243,7 @@ define('pgadmin.node.database', [ if(res.data.info_prefix) { res.info = `${_.escape(res.data.info_prefix)} - ${res.info}`; } - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.removeIcon(i); data.connected = false; data.icon = data.isTemplate ? 'icon-database-template-not-connected':'icon-database-not-connected'; @@ -258,14 +257,14 @@ define('pgadmin.node.database', [ } else { try { - Notify.error(res.errormsg); + pgAdmin.Browser.notifier.error(res.errormsg); } catch (e) { console.warn(e.stack || e); } t.unload(i); } }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.unload(i); }); }, @@ -408,7 +407,7 @@ define('pgadmin.node.database', [ tree.setInode(_item); let dbIcon = data.isTemplate ? 'icon-database-template-not-connected':'icon-database-not-connected'; tree.addIcon(_item, {icon: dbIcon}); - Notify.pgNotifier(fun_error, error, gettext('Connect to database.')); + pgAdmin.Browser.notifier.pgNotifier(fun_error, error, gettext('Connect to database.')); } ); } else { @@ -418,7 +417,7 @@ define('pgadmin.node.database', [ tree.addIcon(_item, {icon: dbIcon}); } - Notify.pgNotifier('error', error, 'Error', function(msg) { + pgAdmin.Browser.notifier.pgNotifier('error', error, 'Error', function(msg) { setTimeout(function() { if (msg == 'CRYPTKEY_SET') { connect_to_database(_model, _data, _tree, _item, _wasConnected); @@ -454,9 +453,9 @@ define('pgadmin.node.database', [ res.info = `${_.escape(res.data.info_prefix)} - ${res.info}`; } if(res.data.already_connected) { - Notify.info(res.info); + pgAdmin.Browser.notifier.info(res.info); } else { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); } pgBrowser.Events.trigger( 'pgadmin:database:connected', _item, _data diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js index 19ef10c25..80c002f19 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js @@ -10,7 +10,7 @@ import { getNodeListByName } from '../../../../../../static/js/node_ajax'; import SubscriptionSchema from './subscription.ui'; import getApiInstance from '../../../../../../../static/js/api_instance'; import _ from 'lodash'; -import Notify from '../../../../../../../static/js/helpers/Notifier'; +import pgAdmin from 'sources/pgadmin'; define('pgadmin.node.subscription', [ 'sources/gettext', 'sources/url_for', @@ -100,12 +100,12 @@ define('pgadmin.node.subscription', [ .then(res=>{ if ((res.data.errormsg === '') && !_.isNull(res.data.data)){ resolve(res.data.data); - Notify.info( + pgAdmin.Browser.notifier.info( gettext('Publication fetched successfully.') ); }else if(!_.isNull(res.data.errormsg) && _.isNull(res.data.data)){ reject(res.data.errormsg); - Notify.alert( + pgAdmin.Browser.notifier.alert( gettext('Check connection?'), gettext(res.data.errormsg) ); diff --git a/web/pgadmin/browser/server_groups/servers/pgagent/static/js/pga_job.js b/web/pgadmin/browser/server_groups/servers/pgagent/static/js/pga_job.js index 5003d5466..f2e5e0d47 100644 --- a/web/pgadmin/browser/server_groups/servers/pgagent/static/js/pga_job.js +++ b/web/pgadmin/browser/server_groups/servers/pgagent/static/js/pga_job.js @@ -10,13 +10,13 @@ import { getNodeAjaxOptions } from '../../../../../static/js/node_ajax'; import PgaJobSchema from './pga_job.ui'; import { getNodePgaJobStepSchema } from '../../steps/static/js/pga_jobstep.ui'; -import Notify from '../../../../../../static/js/helpers/Notifier'; import getApiInstance from '../../../../../../static/js/api_instance'; +import pgAdmin from 'sources/pgadmin'; define('pgadmin.node.pga_job', [ - 'sources/gettext', 'sources/url_for', 'jquery', 'pgadmin.browser', + 'sources/gettext', 'sources/url_for', 'pgadmin.browser', 'pgadmin.node.pga_jobstep', 'pgadmin.node.pga_schedule', -], function(gettext, url_for, $, pgBrowser) { +], function(gettext, url_for, pgBrowser) { if (!pgBrowser.Nodes['coll-pga_job']) { pgBrowser.Nodes['coll-pga_job'] = @@ -95,10 +95,10 @@ define('pgadmin.node.pga_job', [ getApiInstance().put( obj.generate_url(i, 'run_now', d, true), ).then(({data: res})=> { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.unload(i); }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.unload(i); }); } diff --git a/web/pgadmin/browser/server_groups/servers/roles/static/js/roleReassign.js b/web/pgadmin/browser/server_groups/servers/roles/static/js/roleReassign.js index 65c33fe12..fa95e9dc7 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/static/js/roleReassign.js +++ b/web/pgadmin/browser/server_groups/servers/roles/static/js/roleReassign.js @@ -12,8 +12,6 @@ import BaseUISchema from 'sources/SchemaView/base_schema.ui'; import url_for from 'sources/url_for'; import { getNodeListByName, generateNodeUrl } from '../../../../../static/js/node_ajax'; import pgBrowser from 'top/browser/static/js/browser'; -import { getUtilityView } from '../../../../../static/js/utility_view'; -import Notify from '../../../../../../static/js/helpers/Notifier'; import { isEmptyString } from 'sources/validators'; import pgAdmin from 'sources/pgadmin'; @@ -180,17 +178,6 @@ export default class RoleReassign extends BaseUISchema{ } } -function saveCallBack (data) { - if (data.errormsg) { - Notify.alert( - gettext('Error'), - gettext(data.errormsg) - ); - } else { - Notify.success(gettext(data.info)); - } -} - function getUISchema(treeNodeInfo, itemNodeData ) { return new RoleReassign( { @@ -211,13 +198,7 @@ export function showRoleReassign() { treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(item), itemNodeData = pgBrowser.tree.findNodeByDomElement(item).getData(); - pgBrowser.Node.registerUtilityPanel(); - let panel = pgBrowser.Node.addUtilityPanel(pgBrowser.stdW.md, 480), - j = panel.$container.find('.obj_properties').first(); - panel.title(gettext(`Reassign/Drop Owned - ${data.label}`)); - panel.focus(); - - const baseUrl = generateNodeUrl.call( pgAdmin.Browser.Nodes[data._type], treeNodeInfo, 'reassign', data, true); + const urlBase = generateNodeUrl.call( pgAdmin.Browser.Nodes[data._type], treeNodeInfo, 'reassign', data, true); let schema = getUISchema(treeNodeInfo, itemNodeData), sqlHelpUrl = '', @@ -227,6 +208,9 @@ export function showRoleReassign() { 'filename': 'role_reassign_dialog.html', }); - getUtilityView( - schema, treeNodeInfo, 'create', 'dialog', j[0], panel, saveCallBack, extraData, 'Reassign/Drop', baseUrl, sqlHelpUrl, helpUrl); -} \ No newline at end of file + pgAdmin.Browser.Events.trigger('pgadmin:utility:show', item, + gettext(gettext(`Reassign/Drop Owned - ${data.label}`), treeNodeInfo.table.label),{ + schema, extraData, urlBase, sqlHelpUrl, helpUrl, saveBtnName: gettext('Reassign/Drop'), + }, pgAdmin.Browser.stdW.md + ); +} diff --git a/web/pgadmin/browser/server_groups/servers/static/js/binary_path.ui.js b/web/pgadmin/browser/server_groups/servers/static/js/binary_path.ui.js index ae2dadb22..3ebe88ea2 100644 --- a/web/pgadmin/browser/server_groups/servers/static/js/binary_path.ui.js +++ b/web/pgadmin/browser/server_groups/servers/static/js/binary_path.ui.js @@ -12,7 +12,6 @@ import _ from 'lodash'; import url_for from 'sources/url_for'; import BaseUISchema from 'sources/SchemaView/base_schema.ui'; import getApiInstance from '../../../../../static/js/api_instance'; -import Notify from '../../../../../static/js/helpers/Notifier'; import pgAdmin from 'sources/pgadmin'; export function getBinaryPathSchema() { @@ -60,15 +59,15 @@ export default class BinaryPathSchema extends BaseUISchema { validate: (data) => { const api = getApiInstance(); if (_.isNull(data) || data.trim() === '') { - Notify.alert(gettext('Validate Path'), gettext('Path should not be empty.')); + pgAdmin.Browser.notifier.alert(gettext('Validate Path'), gettext('Path should not be empty.')); } else { api.post(url_for('misc.validate_binary_path'), JSON.stringify({ 'utility_path': data })) .then(function (res) { - Notify.alert(gettext('Validate binary path'), gettext(res.data.data)); + pgAdmin.Browser.notifier.alert(gettext('Validate binary path'), gettext(res.data.data)); }) .catch(function (error) { - Notify.pgNotifier('error', error, gettext('Failed to validate binary path.')); + pgAdmin.Browser.notifier.pgNotifier('error', error, gettext('Failed to validate binary path.')); }); } return true; diff --git a/web/pgadmin/browser/server_groups/servers/static/js/server.js b/web/pgadmin/browser/server_groups/servers/static/js/server.js index 5e5f65484..1792d4b3d 100644 --- a/web/pgadmin/browser/server_groups/servers/static/js/server.js +++ b/web/pgadmin/browser/server_groups/servers/static/js/server.js @@ -9,18 +9,17 @@ import { getNodeListById } from '../../../../static/js/node_ajax'; import ServerSchema from './server.ui'; -import Notify from '../../../../../static/js/helpers/Notifier'; import { showServerPassword, showChangeServerPassword, showNamedRestorePoint } from '../../../../../static/js/Dialogs/index'; import _ from 'lodash'; import getApiInstance, { parseApiError } from '../../../../../static/js/api_instance'; define('pgadmin.node.server', [ - 'sources/gettext', 'sources/url_for', 'jquery', + 'sources/gettext', 'sources/url_for', 'sources/pgadmin', 'pgadmin.browser', 'pgadmin.user_management.current_user', 'pgadmin.authenticate.kerberos', ], function( - gettext, url_for, $, pgAdmin, pgBrowser, + gettext, url_for, pgAdmin, pgBrowser, current_user, Kerberos, ) { @@ -42,6 +41,12 @@ define('pgadmin.node.server', [ can_expand: function(d) { return d && d.connected; }, + title: function(d, action) { + if(action == 'create') { + return gettext('Register - %s', this.label); + } + return d.label??''; + }, Init: function() { /* Avoid multiple registration of same menus */ if (this.initialized) @@ -201,7 +206,7 @@ define('pgadmin.node.server', [ obj.generate_url(i, 'connect', d, true), ).then(({data: res})=> { if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info, null); d = t.itemData(i); t.removeIcon(i); d.connected = false; @@ -226,7 +231,7 @@ define('pgadmin.node.server', [ } else { try { - Notify.error(res.errormsg); + pgAdmin.Browser.notifier.error(res.errormsg); } catch (e) { console.warn(e.stack || e); } @@ -234,13 +239,13 @@ define('pgadmin.node.server', [ } } }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.unload(i); }); }; if (notify) { - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Disconnect from server'), gettext('Are you sure you want to disconnect from the server %s?', d.label), function() { disconnect(); }, @@ -293,7 +298,7 @@ define('pgadmin.node.server', [ d = i ? t.itemData(i) : undefined; if (d) { - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Reload server configuration'), gettext('Are you sure you want to reload the server configuration on %s?', d.label), function() { @@ -301,13 +306,13 @@ define('pgadmin.node.server', [ obj.generate_url(i, 'reload', d, true), ).then(({data: res})=> { if (res.data.status) { - Notify.success(res.data.result); + pgAdmin.Browser.notifier.success(res.data.result); } else { - Notify.error(res.data.result); + pgAdmin.Browser.notifier.error(res.data.result); } }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.unload(i); }); }, @@ -351,7 +356,7 @@ define('pgadmin.node.server', [ } showChangeServerPassword(gettext('Change Password'), d, obj, i, is_pgpass_file_used); }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); }); } @@ -360,7 +365,7 @@ define('pgadmin.node.server', [ on_done: function(res, t, i) { if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.itemData(i).wal_pause=res.data.wal_pause; t.deselect(i); // Fetch updated data from server @@ -386,7 +391,7 @@ define('pgadmin.node.server', [ ).then(({data: res})=> { obj.callbacks.on_done(res, t, i); }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.unload(i); }); }, @@ -407,7 +412,7 @@ define('pgadmin.node.server', [ ).then(({data: res})=> { obj.callbacks.on_done(res, t, i); }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); t.unload(i); }); }, @@ -421,7 +426,7 @@ define('pgadmin.node.server', [ d = i ? t.itemData(i) : undefined; if (d) { - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Clear saved password'), gettext('Are you sure you want to clear the saved password for server %s?', d.label), function() { @@ -429,7 +434,7 @@ define('pgadmin.node.server', [ obj.generate_url(i, 'clear_saved_password' , d, true) ).then(({data: res})=> { if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.itemData(i).is_password_saved=res.data.is_password_saved; t.deselect(i); setTimeout(function() { @@ -437,10 +442,10 @@ define('pgadmin.node.server', [ }); } else { - Notify.error(res.info); + pgAdmin.Browser.notifier.error(res.info); } }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); }); }, function() { return true; } @@ -459,7 +464,7 @@ define('pgadmin.node.server', [ d = i ? t.itemData(i) : undefined; if (d) { - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Clear SSH Tunnel password'), gettext('Are you sure you want to clear the saved password of SSH Tunnel for server %s?', d.label), function() { @@ -467,14 +472,14 @@ define('pgadmin.node.server', [ obj.generate_url(i, 'clear_sshtunnel_password' , d, true) ).then(({data: res})=> { if (res.success == 1) { - Notify.success(res.info); + pgAdmin.Browser.notifier.success(res.info); t.itemData(i).is_tunnel_password_saved=res.data.is_tunnel_password_saved; } else { - Notify.error(res.info); + pgAdmin.Browser.notifier.error(res.info); } }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); }); }, function() { return true; } @@ -542,7 +547,7 @@ define('pgadmin.node.server', [ pgBrowser.Events.on( 'pgadmin:server:connect:cancelled', disconnect ); - Notify.confirm( + pgAdmin.Browser.notifier.confirm( gettext('Connection lost'), gettext('Would you like to reconnect to the database?'), function() { @@ -565,12 +570,12 @@ define('pgadmin.node.server', [ let checkSupportedVersion = function (version, info) { if (!_.isUndefined(version) && !_.isNull(version) && version < 100000) { - Notify.warning(gettext('You have connected to a server version that is older ' + + pgAdmin.Browser.notifier.warning(gettext('You have connected to a server version that is older ' + 'than is supported by pgAdmin. This may cause pgAdmin to break in strange and ' + 'unpredictable ways. Or a plague of frogs. Either way, you have been warned!') + '

' + gettext('Server connected'), null); } else if (!_.isUndefined(info) && !_.isNull(info)) { - Notify.success(info); + pgAdmin.Browser.notifier.success(info); } }; @@ -588,7 +593,7 @@ define('pgadmin.node.server', [ data.is_connecting = false; tree.unload(item); tree.addIcon(item, {icon: 'icon-shared-server-not-connected'}); - Notify.info('Please enter the server details to connect to the server. This server is a shared server.'); + pgAdmin.Browser.notifier.info('Please enter the server details to connect to the server. This server is a shared server.'); } else { data.is_connecting = false; tree.unload(item); @@ -629,11 +634,11 @@ define('pgadmin.node.server', [ }, function() { tree.addIcon(_item, {icon: 'icon-server-not-connected'}); - Notify.pgNotifier('error', error, 'Connection error', gettext('Connect to server.')); + pgAdmin.Browser.notifier.pgNotifier('error', error, 'Connection error', gettext('Connect to server.')); } ); } else { - Notify.pgNotifier('error', error, errormsg, function(msg) { + pgAdmin.Browser.notifier.pgNotifier('error', error, errormsg, function(msg) { setTimeout(function() { if (msg == 'CRYPTKEY_SET') { connect_to_server(_node, _data, _tree, _item, _wasConnected); @@ -768,7 +773,7 @@ define('pgadmin.node.server', [ serverInfo[data._id] = _.extend({}, data); if(data.errmsg) { - Notify.error(data.errmsg); + pgAdmin.Browser.notifier.error(data.errmsg); } // Generate the event that server is connected pgBrowser.Events.trigger( @@ -783,7 +788,7 @@ define('pgadmin.node.server', [ }else{ tree.addIcon(item, {icon: 'icon-server-not-connected'}); } - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); }); }; } diff --git a/web/pgadmin/browser/static/js/MainMenuFactory.js b/web/pgadmin/browser/static/js/MainMenuFactory.js index 8ddeaf087..e25ff9bc0 100644 --- a/web/pgadmin/browser/static/js/MainMenuFactory.js +++ b/web/pgadmin/browser/static/js/MainMenuFactory.js @@ -11,7 +11,6 @@ import pgAdmin from 'sources/pgadmin'; import Menu, { MenuItem } from '../../../static/js/helpers/Menu'; import getApiInstance from '../../../static/js/api_instance'; import url_for from 'sources/url_for'; -import Notifier from '../../../static/js/helpers/Notifier'; import { getBrowser } from '../../../static/js/utils'; import { isMac } from '../../../static/js/keyboard_shortcuts'; @@ -98,7 +97,7 @@ export default class MainMenuFactory { ).then(()=>{ window.open(options.url); }).catch(()=>{ - Notifier.error(gettext('Error in opening window')); + pgAdmin.Browser.notifier.error(gettext('Error in opening window')); }); } } diff --git a/web/pgadmin/browser/static/js/activity.js b/web/pgadmin/browser/static/js/activity.js index 2ecb08cfb..6d3025fed 100644 --- a/web/pgadmin/browser/static/js/activity.js +++ b/web/pgadmin/browser/static/js/activity.js @@ -7,7 +7,6 @@ // ////////////////////////////////////////////////////////////// -import $ from 'jquery'; import _ from 'lodash'; import pgAdmin from 'sources/pgadmin'; @@ -106,7 +105,6 @@ _.extend(pgBrowser, { if(self.is_inactivity_timeout()) { clearInterval(timeout_daemon_id); self.inactivity_timeout_daemon_running = false; - $(window).off('beforeunload'); self.logout_inactivity_user(); } }, MIN_ACTIVITY_TIME_UNIT); diff --git a/web/pgadmin/browser/static/js/browser.js b/web/pgadmin/browser/static/js/browser.js index f10a29eb4..13d6a7f03 100644 --- a/web/pgadmin/browser/static/js/browser.js +++ b/web/pgadmin/browser/static/js/browser.js @@ -7,45 +7,25 @@ // ////////////////////////////////////////////////////////////// -import React from 'react'; -import { generateNodeUrl } from './node_ajax'; import MainMenuFactory from './MainMenuFactory'; import _ from 'lodash'; -import Notify, {initializeModalProvider, initializeNotifier} from '../../../static/js/helpers/Notifier'; -import { checkMasterPassword } from '../../../static/js/Dialogs/index'; +import { checkMasterPassword, showQuickSearch } from '../../../static/js/Dialogs/index'; import { pgHandleItemError } from '../../../static/js/utils'; -import { Search } from './quick_search/trigger_search'; import { send_heartbeat, stop_heartbeat } from './heartbeat'; import getApiInstance from '../../../static/js/api_instance'; -import { copyToClipboard } from '../../../static/js/clipboard'; -import { TAB_CHANGE } from './constants'; +import usePreferences, { setupPreferenceBroadcast } from '../../../preferences/static/js/store'; +import checkNodeVisibility from '../../../static/js/check_node_visibility'; define('pgadmin.browser', [ - 'sources/gettext', 'sources/url_for', 'jquery', - 'sources/pgadmin', 'bundled_codemirror', - 'sources/check_node_visibility', './toolbar', 'pgadmin.help', - 'sources/csrf', 'sources/utils', 'sources/window', 'pgadmin.authenticate.kerberos', - 'sources/tree/tree_init', - 'pgadmin.browser.utils', - 'pgadmin.browser.preferences', 'pgadmin.browser.messages', - 'pgadmin.browser.panel', 'pgadmin.browser.layout', - 'pgadmin.browser.frame', + 'sources/gettext', 'sources/url_for', 'sources/pgadmin', 'bundled_codemirror', + 'sources/csrf', 'pgadmin.authenticate.kerberos', + 'pgadmin.browser.utils', 'pgadmin.browser.messages', 'pgadmin.browser.node', 'pgadmin.browser.collection', 'pgadmin.browser.activity', 'sources/codemirror/addon/fold/pgadmin-sqlfoldcode', 'pgadmin.browser.keyboard', 'sources/tree/pgadmin_tree_save_state', - /* wcDocker dependencies */ - 'bootstrap', 'jquery-contextmenu', 'wcdocker', ], function( - gettext, url_for, $, - pgAdmin, codemirror, - checkNodeVisibility, toolBar, help, csrfToken, pgadminUtils, pgWindow, - Kerberos, InitTree, + gettext, url_for, pgAdmin, codemirror, csrfToken, Kerberos, ) { - window.jQuery = window.$ = $; - // Some scripts do export their object in the window only. - // Generally the one, which do no have AMD support. - let wcDocker = window.wcDocker; - $ = $ || window.jQuery || window.$; let CodeMirror = codemirror.default; let pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}; @@ -55,104 +35,10 @@ define('pgadmin.browser', [ Kerberos.validate_kerberos_ticket(); - let panelEvents = {}; - panelEvents[wcDocker.EVENT.VISIBILITY_CHANGED] = function() { - if (this.isVisible()) { - let obj = pgAdmin.Browser, - i = obj.tree ? obj.tree.selected() : undefined, - d = i ? obj.tree.itemData(i) : undefined; - - if (d && obj.Nodes[d._type].callbacks['selected'] && - _.isFunction(obj.Nodes[d._type].callbacks['selected'])) { - return obj.Nodes[d._type].callbacks['selected'].apply( - obj.Nodes[d._type], [i, d, obj, [], '', TAB_CHANGE]); - } - } - }; - - let initializeBrowserTree = pgAdmin.Browser.initializeBrowserTree = - function(b) { - const draggableTypes = [ - 'collation domain domain_constraints fts_configuration fts_dictionary fts_parser fts_template synonym table partition type sequence package view mview foreign_table edbvar', - 'schema column database cast event_trigger extension language foreign_data_wrapper foreign_server user_mapping compound_trigger index index_constraint primary_key unique_constraint check_constraint exclusion_constraint foreign_key rule', - 'trigger trigger_function', - 'edbfunc function edbproc procedure' - ]; - InitTree.initBrowserTree(b).then(() => { - const getQualifiedName = (data, item)=>{ - if(draggableTypes[0].includes(data._type)) { - return pgadminUtils.fully_qualify(b, data, item); - } else if(draggableTypes[1].includes(data._type)) { - return pgadminUtils.quote_ident(data._label); - } else if(draggableTypes[3].includes(data._type)) { - let newData = {...data}; - let parsedFunc = pgadminUtils.parseFuncParams(newData._label); - newData._label = parsedFunc.func_name; - return pgadminUtils.fully_qualify(b, newData, item); - } else { - return data._label; - } - }; - - b.tree.registerDraggableType({ - [draggableTypes[0]] : (data, item, treeNodeInfo)=>{ - let text = getQualifiedName(data, item); - return { - text: text, - objUrl: generateNodeUrl.call(pgBrowser.Nodes[data._type], treeNodeInfo, 'properties', data, true), - nodeType: data._type, - cur: { - from: text.length, - to: text.length, - }, - }; - }, - [draggableTypes[1]] : (data)=>{ - return getQualifiedName(data); - }, - [draggableTypes[2]] : (data)=>{ - return getQualifiedName(data); - }, - [draggableTypes[3]] : (data, item)=>{ - let parsedFunc = pgadminUtils.parseFuncParams(data._label), - dropVal = getQualifiedName(data, item), - curPos = {from: 0, to: 0}; - - if(parsedFunc.params.length > 0) { - dropVal = dropVal + '('; - curPos.from = dropVal.length; - dropVal = dropVal + parsedFunc.params[0][0]; - curPos.to = dropVal.length; - - for(let i=1; i{ - copyToClipboard(getQualifiedName(data, item)); - }); - }, () => {console.warn('Tree Load Error');}); - }; - // Extend the browser class attributes _.extend(pgAdmin.Browser, { // The base url for browser URL: url_for('browser.index'), - // We do have docker of type wcDocker to take care of different - // containers. (i.e. panels, tabs, frames, etc.) docker:null, // Reversed Engineer query for the selected database node object goes // here @@ -215,102 +101,7 @@ define('pgadmin.browser', [ }, }, // Default panels - panels: { - // Panel to keep the left hand browser tree - 'browser': new pgAdmin.Browser.Panel({ - name: 'browser', - title: gettext('Object Explorer'), - showTitle: true, - isCloseable: false, - isPrivate: true, - icon: '', - limit: 1, - content: '
', - onCreate: function(panel, container) { - toolBar.initializeToolbar(panel, wcDocker); - container.classList.add('pg-no-overflow'); - }, - }), - // Properties of the object node - 'properties': new pgAdmin.Browser.Panel({ - name: 'properties', - title: gettext('Properties'), - icon: '', - width: 500, - isCloseable: false, - isPrivate: true, - elContainer: true, - limit: 1, - content: '
' + select_object_msg + '
', - events: panelEvents, - onCreate: function(myPanel, container) { - container.classList.add('pg-no-overflow'); - }, - }), - // Statistics of the object - 'statistics': new pgAdmin.Browser.Panel({ - name: 'statistics', - title: gettext('Statistics'), - icon: '', - width: 500, - isCloseable: true, - isPrivate: false, - limit : 1, - canHide: true, - content: '
', - events: panelEvents, - }), - // Reversed engineered SQL for the object - 'sql': new pgAdmin.Browser.Panel({ - name: 'sql', - title: gettext('SQL'), - icon: '', - width: 500, - isCloseable: false, - isPrivate: true, - limit: 1, - content: '
', - }), - // Dependencies of the object - 'dependencies': new pgAdmin.Browser.Panel({ - name: 'dependencies', - title: gettext('Dependencies'), - icon: '', - width: 500, - isCloseable: true, - isPrivate: false, - canHide: true, - limit: 1, - content: '
', - events: panelEvents, - }), - // Dependents of the object - 'dependents': new pgAdmin.Browser.Panel({ - name: 'dependents', - title: gettext('Dependents'), - icon: '', - width: 500, - isCloseable: true, - isPrivate: false, - limit: 1, - canHide: true, - content: '
', - events: panelEvents, - }), - // Background processes - 'processes': new pgAdmin.Browser.Panel({ - name: 'processes', - title: gettext('Processes'), - icon: '', - width: 500, - isCloseable: true, - isPrivate: false, - limit: 1, - canHide: true, - content: '
', - events: panelEvents, - }), - }, + panels: {}, // We also support showing dashboards, HTML file, external URL frames: {}, /* Menus */ @@ -336,40 +127,6 @@ define('pgadmin.browser', [ MainMenus: [], BrowserContextMenu: [], - add_panels: function() { - /* Add hooked-in panels by extensions */ - let panels = JSON.parse(pgBrowser.panels_items); - _.each(panels, function(panel) { - if (panel.isIframe) { - pgBrowser.frames[panel.name] = new pgBrowser.Frame({ - name: panel.name, - title: panel.title, - icon: panel.icon, - width: panel.width, - height: panel.height, - showTitle: panel.showTitle, - isCloseable: panel.isCloseable, - isPrivate: panel.isPrivate, - url: panel.content, - }); - } else { - pgBrowser.panels[panel.name] = new pgBrowser.Panel({ - name: panel.name, - title: panel.title, - icon: panel.icon, - width: panel.width, - height: panel.height, - showTitle: panel.showTitle, - isCloseable: panel.isCloseable, - isPrivate: panel.isPrivate, - limit: (panel.limit) ? panel.limit : null, - content: (panel.content) ? panel.content : '', - events: (panel.events) ? panel.events : '', - canHide: (panel.canHide) ? panel.canHide : '', - }); - } - }); - }, menu_categories: { /* name, label (pair) */ 'register': { @@ -490,8 +247,6 @@ define('pgadmin.browser', [ enable_disable_menus: function(item) { let obj = this; let d = item ? obj.tree.itemData(item) : undefined; - toolBar.enable(gettext('View Data'), false); - toolBar.enable(gettext('Filtered Rows'), false); // All menus (except for the object menus) are already present. // They will just require to check, whether they are @@ -529,64 +284,8 @@ define('pgadmin.browser', [ obj.initialized = true; // Cache preferences - obj.cache_preferences(); - obj.add_panels(); - // Initialize the Docker - obj.docker = new wcDocker( - '#dockerContainer', { - allowContextMenu: true, - allowCollapse: false, - loadingClass: 'pg-sp-icon', - themePath: url_for('static', { - 'filename': 'css', - }), - theme: 'webcabin.overrides.css', - }); - if (obj.docker) { - // Initialize all the panels - _.each(obj.panels, function(panel, name) { - obj.panels[name].load(obj.docker); - }); - // Initialize all the frames - _.each(obj.frames, function(frame, name) { - obj.frames[name].load(obj.docker); - }); - - // Stored layout in database from the previous session - let layout = pgBrowser.utils.layout; - obj.restore_layout(obj.docker, layout, obj.buildDefaultLayout.bind(obj), true); - - obj.docker.on(wcDocker.EVENT.LAYOUT_CHANGED, function() { - obj.save_current_layout('Browser/Layout', obj.docker); - }); - } - - initializeBrowserTree(obj); - initializeModalProvider(); - initializeNotifier(); - - /* Cache may take time to load for the first time - * Reflect the changes once cache is available - */ - let cacheIntervalId = setInterval(()=> { - let sqlEditPreferences = obj.get_preferences_for_module('sqleditor'); - let browserPreferences = obj.get_preferences_for_module('browser'); - if(sqlEditPreferences && browserPreferences) { - clearInterval(cacheIntervalId); - obj.reflectPreferences('sqleditor'); - obj.reflectPreferences('browser'); - } - }, 500); - - /* Check for sql editor preference changes */ - obj.onPreferencesChange('sqleditor', function() { - obj.reflectPreferences('sqleditor'); - }); - - /* Check for browser preference changes */ - obj.onPreferencesChange('browser', function() { - obj.reflectPreferences('browser'); - }); + usePreferences.getState().cache(); + setupPreferenceBroadcast(); setTimeout(function() { obj?.editor?.setValue('-- ' + select_object_msg); @@ -621,7 +320,6 @@ define('pgadmin.browser', [ obj.Events.on('pgadmin:browser:tree:update', obj.onUpdateTreeNode.bind(obj)); obj.Events.on('pgadmin:browser:tree:refresh', obj.onRefreshTreeNodeReact.bind(obj)); obj.Events.on('pgadmin-browser:tree:loadfail', obj.onLoadFailNode.bind(obj)); - obj.Events.on('pgadmin-browser:panel-browser:' + wcDocker.EVENT.RESIZE_ENDED, obj.onResizeEnded.bind(obj)); obj.bind_beforeunload(); /* User UI activity */ @@ -629,8 +327,8 @@ define('pgadmin.browser', [ obj.register_to_activity_listener(document); obj.start_inactivity_timeout_daemon(); }, - onResizeEnded: function() { - if (this.tree) this.tree.resizeTree(); + uiloaded: function() { + this.check_version_update(); }, check_corrupted_db_file: function() { getApiInstance().get( @@ -638,7 +336,7 @@ define('pgadmin.browser', [ ).then(({data: res})=> { if(res.data.length > 0) { - Notify.alert( + pgAdmin.Browser.notifier.alert( 'Warning', 'pgAdmin detected unrecoverable corruption in it\'s SQLite configuration database. ' + 'The database has been backed up and recreated with default settings. '+ @@ -649,7 +347,7 @@ define('pgadmin.browser', [ ); } }).catch(function(error) { - Notify.alert(error); + pgAdmin.Browser.notifier.alert(error); }); }, check_master_password: function(on_resp_callback) { @@ -664,7 +362,7 @@ define('pgadmin.browser', [ } } }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); }); }, @@ -677,7 +375,7 @@ define('pgadmin.browser', [ self.set_master_password(''); } }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); }); }, @@ -695,13 +393,33 @@ define('pgadmin.browser', [ checkMasterPassword(data, self.masterpass_callback_queue, cancel_callback); }, - bind_beforeunload: function() { - $(window).on('beforeunload', function(e) { - /* Can open you in new tab */ - let openerBrowser = pgWindow.default.pgAdmin.Browser; + check_version_update: function() { + getApiInstance().get( + url_for('misc.upgrade_check') + ).then((res)=> { + const data = res.data.data; + if(data.outdated) { + pgAdmin.Browser.notifier.warning( + ` + ${gettext('You are currently running version %s of %s,
however the current version is %s.', data.current_version, data.product_name, data.upgrade_version)} +

+ ${gettext('Please click here for more information.', data.download_url)} + `, + null + ); + } - let tree_save_interval = pgBrowser.get_preference('browser', 'browser_tree_state_save_interval'), - confirm_on_refresh_close = openerBrowser.get_preference('browser', 'confirm_on_refresh_close'); + }).catch(function() { + // Suppress any errors + }); + }, + + bind_beforeunload: function() { + window.addEventListener('beforeunload', function(e) { + /* Can open you in new tab */ + const prefStore = usePreferences.getState(); + let tree_save_interval = prefStore.getPreferences('browser', 'browser_tree_state_save_interval'), + confirm_on_refresh_close = prefStore.getPreferences('browser', 'confirm_on_refresh_close'); if (!_.isUndefined(tree_save_interval) && tree_save_interval.value !== -1) pgAdmin.Browser.browserTreeState.save_state(); @@ -709,7 +427,9 @@ define('pgadmin.browser', [ if(!_.isUndefined(confirm_on_refresh_close) && confirm_on_refresh_close.value) { /* This message will not be displayed in Chrome, Firefox, Safari as they have disabled it*/ let msg = gettext('Are you sure you want to close the %s browser?', pgBrowser.utils.app_name); - e.originalEvent.returnValue = msg; + if(e.originalEvent?.returnValue) { + e.originalEvent.returnValue = msg; + } return msg; } }); @@ -730,8 +450,7 @@ define('pgadmin.browser', [ // Add menus of module/extension at appropriate menu add_menus: function(menus) { - let self = this, - pgMenu = this.all_menus_cache; + let pgMenu = this.all_menus_cache; _.each(menus, function(m) { _.each(m.applies, function(a) { @@ -741,12 +460,12 @@ define('pgadmin.browser', [ // If current node is not visible in browser tree // then return from here - if(!checkNodeVisibility(self, m.node)) { + if(!checkNodeVisibility(m.node)) { return; } else if(_.has(m, 'module') && !_.isUndefined(m.module)) { // If module to which this menu applies is not visible in // browser tree then also we do not display menu - if(!checkNodeVisibility(self, m.module.type)) { + if(!checkNodeVisibility(m.module.type)) { return; } } @@ -770,14 +489,9 @@ define('pgadmin.browser', [ } // This is to handel quick search callback - if(gettext(_m.label) == gettext('Quick Search')) { + if(_m.name == 'mnu_quick_search_help') { _m.callback = () => { - // Render Search component - Notify.showModal(gettext('Quick Search'), (closeModal) => { - return ; - }, - { isFullScreen: false, isResizeable: false, showFullScreen: false, isFullWidth: false, showTitle: false} - ); + showQuickSearch(); }; } @@ -1683,7 +1397,6 @@ define('pgadmin.browser', [ if (!n) { ctx.t.destroy({ success: function() { - initializeBrowserTree(ctx.b); ctx.t = ctx.b.tree; ctx.i = null; ctx.b._refreshNode(ctx, ctx.branch); @@ -1760,7 +1473,7 @@ define('pgadmin.browser', [ } } - Notify.pgNotifier('error', error, gettext('Error retrieving details for the node.'), function (msg) { + pgAdmin.Browser.notifier.pgNotifier('error', error, gettext('Error retrieving details for the node.'), function (msg) { if (msg == 'CRYPTKEY_SET') { fetchNodeInfo(__i, __d, __n); } else { @@ -1974,7 +1687,7 @@ define('pgadmin.browser', [ } fetchNodeInfo(_callback); }).catch(function(error) { - Notify.pgRespErrorNotify(error); + pgAdmin.Browser.notifier.pgRespErrorNotify(error); fetchNodeInfo(_callback); }); }; diff --git a/web/pgadmin/browser/static/js/collection.js b/web/pgadmin/browser/static/js/collection.js index c8f78d053..cfe6c8bc9 100644 --- a/web/pgadmin/browser/static/js/collection.js +++ b/web/pgadmin/browser/static/js/collection.js @@ -6,7 +6,6 @@ // This software is released under the PostgreSQL Licence // ////////////////////////////////////////////////////////////// -import {getPanelView} from './panel_view'; import _ from 'lodash'; define([ @@ -84,15 +83,6 @@ define([ canDrop: true, canDropCascade: true, selectParentNodeOnDelete: false, - showProperties: function(item, data, panel) { - let container = panel.$container.find('.obj_properties').first(); - getPanelView( - pgBrowser.tree, - container[0], - pgBrowser, - panel._type - ); - }, generate_url: function(item, type) { /* * Using list, and collection functions of a node to get the nodes diff --git a/web/pgadmin/browser/static/js/constants.js b/web/pgadmin/browser/static/js/constants.js index 03e8c1f81..5fd9bd92b 100644 --- a/web/pgadmin/browser/static/js/constants.js +++ b/web/pgadmin/browser/static/js/constants.js @@ -1,2 +1,34 @@ +export const AUTH_METHODS = { + INTERNAL: 'internal', + LDAP: 'ldap', + KERBEROS: 'kerberos', + OAUTH2: 'oauth2', + WEBSERVER: 'webserver' +}; -export const TAB_CHANGE = 'TAB_CHANGE'; \ No newline at end of file +export const TAB_CHANGE = 'TAB_CHANGE'; + +export const BROWSER_PANELS = { + MAIN: 'id-main', + OBJECT_EXPLORER: 'id-object-explorer', + DASHBOARD: 'id-dashboard', + PROPERTIES: 'id-properties', + SQL: 'id-sql', + STATISTICS: 'id-statistics', + DEPENDENCIES: 'id-dependencies', + DEPENDENTS: 'id-dependents', + PROCESSES: 'id-processes', + PROCESS_DETAILS: 'id-process-details', + EDIT_PROPERTIES: 'id-edit-properties', + UTILITY_DIALOG: 'id-utility', + QUERY_TOOL: 'id-query-tool', + PSQL_TOOL: 'id-psql-tool', + ERD_TOOL: 'id-erd-tool', + SCHEMA_DIFF_TOOL: 'id-schema-diff-tool', + DEBUGGER_TOOL: 'id-debugger-tool', + CLOUD_WIZARD: 'id-cloud-wizard', + GRANT_WIZARD: 'id-grant-wizard', + SEARCH_OBJECTS: 'id-search-objects', + USER_MANAGEMENT: 'id-user-management', + IMPORT_EXPORT_SERVERS: 'id-import-export-servers' +}; diff --git a/web/pgadmin/browser/static/js/frame.js b/web/pgadmin/browser/static/js/frame.js deleted file mode 100644 index adfd7451d..000000000 --- a/web/pgadmin/browser/static/js/frame.js +++ /dev/null @@ -1,135 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2023, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// -import _ from 'lodash'; -define([ - 'sources/pgadmin', 'jquery', 'wcdocker', -], function(pgAdmin, $) { - - let pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}, - wcDocker = window.wcDocker, - wcIFrame = window.wcIFrame; - - pgAdmin.Browser.Frame = function(options) { - let defaults = [ - 'name', 'title', 'width', 'height', 'showTitle', 'isCloseable', - 'isPrivate', 'url', 'icon', 'onCreate', 'isLayoutMember', 'isRenamable', - ]; - _.extend(this, _.pick(options, defaults)); - }; - - _.extend(pgAdmin.Browser.Frame.prototype, { - name: '', - title: '', - width: 300, - height: 600, - showTitle: true, - isClosable: true, - isRenamable: false, - isPrivate: false, - isLayoutMember: false, - url: '', - icon: '', - panel: null, - frame: null, - onCreate: null, - load: function(docker) { - let that = this; - if (!that.panel) { - docker.registerPanelType(this.name, { - title: that.title, - isPrivate: that.isPrivate, - isLayoutMember: that.isLayoutMember, - onCreate: function(myPanel) { - myPanel.initSize(that.width, that.height); - - if (!(myPanel.showTitle??true)) - myPanel.title(false); - - myPanel.icon(that.icon); - - myPanel.closeable(!!that.isCloseable); - myPanel.renamable(that.isRenamable); - - let $frameArea = $('
'); - myPanel.layout().addItem($frameArea); - that.panel = myPanel; - let frame = new wcIFrame($frameArea, myPanel); - - myPanel.frameData = { - pgAdminName: that.name, - frameInitialized: false, - embeddedFrame: frame, - }; - - if (that.url != '' && that.url != 'about:blank') { - setTimeout(function() { - frame.openURL(that.url); - myPanel.frameData.frameInitialized = true; - pgBrowser.Events.trigger( - 'pgadmin-browser:frame:urlloaded:' + that.name, frame, - that.url, self - ); - }, 50); - } else { - frame.openURL('about:blank'); - myPanel.frameData.frameInitialized = true; - pgBrowser.Events.trigger( - 'pgadmin-browser:frame:urlloaded:' + that.name, frame, - that.url, self - ); - } - - if (that.events && _.isObject(that.events)) { - _.each(that.events, function(v, k) { - if (v && _.isFunction(v)) { - myPanel.on(k, v); - } - }); - } - - _.each([ - wcDocker.EVENT.UPDATED, wcDocker.EVENT.VISIBILITY_CHANGED, - wcDocker.EVENT.BEGIN_DOCK, wcDocker.EVENT.END_DOCK, - wcDocker.EVENT.GAIN_FOCUS, wcDocker.EVENT.LOST_FOCUS, - wcDocker.EVENT.CLOSED, wcDocker.EVENT.BUTTON, - wcDocker.EVENT.ATTACHED, wcDocker.EVENT.DETACHED, - wcDocker.EVENT.MOVE_STARTED, wcDocker.EVENT.MOVE_ENDED, - wcDocker.EVENT.MOVED, wcDocker.EVENT.RESIZE_STARTED, - wcDocker.EVENT.RESIZE_ENDED, wcDocker.EVENT.RESIZED, - wcDocker.EVENT.SCROLLED, - ], function(ev) { - myPanel.on(ev, that.eventFunc.bind(myPanel, ev)); - }); - - if (that.onCreate && _.isFunction(that.onCreate)) { - that.onCreate.apply(that, [myPanel, frame]); - } - }, - }); - } - }, - eventFunc: function(eventName) { - let name = this.frameData.pgAdminName; - - try { - pgBrowser.Events.trigger('pgadmin-browser:frame', eventName, this, arguments); - pgBrowser.Events.trigger('pgadmin-browser:frame:' + eventName, this, arguments); - - if (name) { - pgBrowser.Events.trigger('pgadmin-browser:frame-' + name, eventName, this, arguments); - pgBrowser.Events.trigger('pgadmin-browser:frame-' + name + ':' + eventName, this, arguments); - } - } catch (e) { - console.warn(e.stack || e); - } - }, - }); - - return pgAdmin.Browser.Frame; -}); diff --git a/web/pgadmin/browser/static/js/heartbeat.js b/web/pgadmin/browser/static/js/heartbeat.js index c526a310f..4409955e7 100644 --- a/web/pgadmin/browser/static/js/heartbeat.js +++ b/web/pgadmin/browser/static/js/heartbeat.js @@ -10,7 +10,6 @@ import gettext from 'sources/gettext'; import url_for from 'sources/url_for'; import getApiInstance from '../../../static/js/api_instance'; -import Notifier from '../../../static/js/helpers/Notifier'; import pgAdmin from 'sources/pgadmin'; const axiosApi = getApiInstance(); @@ -28,9 +27,9 @@ export function send_heartbeat(_server_id, _item) { }) .catch((error) => { if (error && error.message == 'Network Error') { - Notifier.error(gettext(`pgAdmin server not responding, try to login again: ${error.message || error.response.data.errormsg}`)); + pgAdmin.Browser.notifier.error(gettext(`pgAdmin server not responding, try to login again: ${error.message || error.response.data.errormsg}`)); } else { - Notifier.error(gettext(`Server heartbeat logging error: ${error.message || error.response.data.errormsg}`)); + pgAdmin.Browser.notifier.error(gettext(`Server heartbeat logging error: ${error.message || error.response.data.errormsg}`)); } stop_heartbeat(_item); }); diff --git a/web/pgadmin/browser/static/js/keyboard.js b/web/pgadmin/browser/static/js/keyboard.js index 996d870b2..2a7db39b5 100644 --- a/web/pgadmin/browser/static/js/keyboard.js +++ b/web/pgadmin/browser/static/js/keyboard.js @@ -13,6 +13,7 @@ import Mousetrap from 'mousetrap'; import * as commonUtils from '../../../static/js/utils'; import gettext from 'sources/gettext'; import pgWindow from 'sources/window'; +import usePreferences from '../../../preferences/static/js/store'; const pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}; @@ -20,51 +21,53 @@ pgBrowser.keyboardNavigation = pgBrowser.keyboardNavigation || {}; _.extend(pgBrowser.keyboardNavigation, { init: function() { - Mousetrap.reset(); - if (pgBrowser.preferences_cache.length > 0) { - this.keyboardShortcut = { - ...(pgBrowser.get_preference('browser', 'main_menu_file')?.value) && {'file_shortcut': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_file')?.value)}, - ...(pgBrowser.get_preference('browser', 'main_menu_object')?.value) && {'object_shortcut': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_object')?.value)}, - ...(pgBrowser.get_preference('browser', 'main_menu_tools')?.value) && {'tools_shortcut': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_tools')?.value)}, - ...(pgBrowser.get_preference('browser', 'main_menu_help')?.value) && {'help_shortcut': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_help')?.value)}, - 'left_tree_shortcut': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'browser_tree').value), - 'tabbed_panel_backward': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'tabbed_panel_backward').value), - 'tabbed_panel_forward': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'tabbed_panel_forward').value), - 'sub_menu_query_tool': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_query_tool').value), - 'sub_menu_view_data': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_view_data').value), - 'sub_menu_search_objects': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_search_objects').value), - 'sub_menu_properties': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_properties').value), - 'sub_menu_create': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_create').value), - 'sub_menu_delete': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_delete').value), - 'sub_menu_refresh': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_refresh').value), - 'context_menu': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'context_menu').value), - 'direct_debugging': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'direct_debugging').value), - 'add_grid_row': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'add_grid_row').value), - 'open_quick_search': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'open_quick_search').value), + usePreferences.subscribe((prefStore)=>{ + Mousetrap.reset(); + if (prefStore.version > 0) { + this.keyboardShortcut = { + ...(prefStore.getPreferences('browser', 'main_menu_file')?.value) && {'file_shortcut': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'main_menu_file')?.value)}, + ...(prefStore.getPreferences('browser', 'main_menu_object')?.value) && {'object_shortcut': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'main_menu_object')?.value)}, + ...(prefStore.getPreferences('browser', 'main_menu_tools')?.value) && {'tools_shortcut': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'main_menu_tools')?.value)}, + ...(prefStore.getPreferences('browser', 'main_menu_help')?.value) && {'help_shortcut': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'main_menu_help')?.value)}, + 'left_tree_shortcut': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'browser_tree').value), + 'tabbed_panel_backward': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'tabbed_panel_backward').value), + 'tabbed_panel_forward': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'tabbed_panel_forward').value), + 'sub_menu_query_tool': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'sub_menu_query_tool').value), + 'sub_menu_view_data': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'sub_menu_view_data').value), + 'sub_menu_search_objects': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'sub_menu_search_objects').value), + 'sub_menu_properties': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'sub_menu_properties').value), + 'sub_menu_create': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'sub_menu_create').value), + 'sub_menu_delete': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'sub_menu_delete').value), + 'sub_menu_refresh': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'sub_menu_refresh').value), + 'context_menu': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'context_menu').value), + 'direct_debugging': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'direct_debugging').value), + 'add_grid_row': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'add_grid_row').value), + 'open_quick_search': commonUtils.parseShortcutValue(prefStore.getPreferences('browser', 'open_quick_search').value), - }; - this.shortcutMethods = { - ...(pgBrowser.get_preference('browser', 'main_menu_file')?.value) && {'bindMainMenu': { - 'shortcuts': [this.keyboardShortcut.file_shortcut, - this.keyboardShortcut.object_shortcut, this.keyboardShortcut.tools_shortcut, - this.keyboardShortcut.help_shortcut], - }}, // Main menu - 'bindRightPanel': {'shortcuts': [this.keyboardShortcut.tabbed_panel_backward, this.keyboardShortcut.tabbed_panel_forward]}, // Main window panels - 'bindLeftTree': {'shortcuts': this.keyboardShortcut.left_tree_shortcut}, // Main menu, - 'bindSubMenuQueryTool': {'shortcuts': this.keyboardShortcut.sub_menu_query_tool}, // Sub menu - Open Query Tool, - 'bindSubMenuViewData': {'shortcuts': this.keyboardShortcut.sub_menu_view_data}, // Sub menu - Open View Data, - 'bindSubMenuSearchObjects': {'shortcuts': this.keyboardShortcut.sub_menu_search_objects}, // Sub menu - Open search objects, - 'bindSubMenuProperties': {'shortcuts': this.keyboardShortcut.sub_menu_properties}, // Sub menu - Edit Properties, - 'bindSubMenuCreate': {'shortcuts': this.keyboardShortcut.sub_menu_create}, // Sub menu - Create Object, - 'bindSubMenuDelete': {'shortcuts': this.keyboardShortcut.sub_menu_delete}, // Sub menu - Delete object, - 'bindSubMenuRefresh': {'shortcuts': this.keyboardShortcut.sub_menu_refresh, 'bindElem': '#tree'}, // Sub menu - Refresh object, - 'bindContextMenu': {'shortcuts': this.keyboardShortcut.context_menu}, // Sub menu - Open context menu, - 'bindDirectDebugging': {'shortcuts': this.keyboardShortcut.direct_debugging}, // Sub menu - Direct Debugging - 'bindAddGridRow': {'shortcuts': this.keyboardShortcut.add_grid_row}, // Subnode Grid Add Row - 'bindOpenQuickSearch': {'shortcuts': this.keyboardShortcut.open_quick_search}, // Subnode Grid Refresh Row - }; - this.bindShortcuts(); - } + }; + this.shortcutMethods = { + ...(prefStore.getPreferences('browser', 'main_menu_file')?.value) && {'bindMainMenu': { + 'shortcuts': [this.keyboardShortcut.file_shortcut, + this.keyboardShortcut.object_shortcut, this.keyboardShortcut.tools_shortcut, + this.keyboardShortcut.help_shortcut], + }}, // Main menu + 'bindRightPanel': {'shortcuts': [this.keyboardShortcut.tabbed_panel_backward, this.keyboardShortcut.tabbed_panel_forward]}, // Main window panels + 'bindLeftTree': {'shortcuts': this.keyboardShortcut.left_tree_shortcut}, // Main menu, + 'bindSubMenuQueryTool': {'shortcuts': this.keyboardShortcut.sub_menu_query_tool}, // Sub menu - Open Query Tool, + 'bindSubMenuViewData': {'shortcuts': this.keyboardShortcut.sub_menu_view_data}, // Sub menu - Open View Data, + 'bindSubMenuSearchObjects': {'shortcuts': this.keyboardShortcut.sub_menu_search_objects}, // Sub menu - Open search objects, + 'bindSubMenuProperties': {'shortcuts': this.keyboardShortcut.sub_menu_properties}, // Sub menu - Edit Properties, + 'bindSubMenuCreate': {'shortcuts': this.keyboardShortcut.sub_menu_create}, // Sub menu - Create Object, + 'bindSubMenuDelete': {'shortcuts': this.keyboardShortcut.sub_menu_delete}, // Sub menu - Delete object, + 'bindSubMenuRefresh': {'shortcuts': this.keyboardShortcut.sub_menu_refresh, 'bindElem': '#tree'}, // Sub menu - Refresh object, + 'bindContextMenu': {'shortcuts': this.keyboardShortcut.context_menu}, // Sub menu - Open context menu, + 'bindDirectDebugging': {'shortcuts': this.keyboardShortcut.direct_debugging}, // Sub menu - Direct Debugging + 'bindAddGridRow': {'shortcuts': this.keyboardShortcut.add_grid_row}, // Subnode Grid Add Row + 'bindOpenQuickSearch': {'shortcuts': this.keyboardShortcut.open_quick_search}, // Subnode Grid Refresh Row + }; + this.bindShortcuts(); + } + }); }, bindShortcuts: function() { const self = this; @@ -116,7 +119,7 @@ _.extend(pgBrowser.keyboardNavigation, { } if(menuLabel) { - document.querySelector(`#main-menu-container button[data-label="${menuLabel}"]`)?.click(); + document.querySelector(`div[data-test="app-menu-bar"] button[data-label="${menuLabel}"]`)?.click(); } }, bindRightPanel: function(event, combo) { diff --git a/web/pgadmin/browser/static/js/layout.js b/web/pgadmin/browser/static/js/layout.js deleted file mode 100644 index ade9709d6..000000000 --- a/web/pgadmin/browser/static/js/layout.js +++ /dev/null @@ -1,170 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2023, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// - -import pgAdmin from 'sources/pgadmin'; -import url_for from 'sources/url_for'; -import gettext from 'sources/gettext'; -import 'wcdocker'; -import pgWindow from 'sources/window'; -import Notify from '../../../static/js/helpers/Notifier'; -import getApiInstance from '../../../static/js/api_instance'; - -const pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}; - -let wcDocker = window.wcDocker; - -/* Add cache related methods and properties */ -_.extend(pgBrowser, { - lock_layout_levels : { - PREVENT_DOCKING: 'docking', - FULL: 'full', - NONE: 'none', - }, - - // Build the default layout - buildDefaultLayout: function(docker) { - let browserPanel = docker.addPanel('browser', wcDocker.DOCK.LEFT); - let dashboardPanel = docker.addPanel( - 'dashboard', wcDocker.DOCK.RIGHT, browserPanel); - docker.addPanel('properties', wcDocker.DOCK.STACKED, dashboardPanel, { - tabOrientation: wcDocker.TAB.TOP, - }); - docker.addPanel('sql', wcDocker.DOCK.STACKED, dashboardPanel); - docker.addPanel( - 'statistics', wcDocker.DOCK.STACKED, dashboardPanel); - docker.addPanel( - 'dependencies', wcDocker.DOCK.STACKED, dashboardPanel); - docker.addPanel( - 'dependents', wcDocker.DOCK.STACKED, dashboardPanel); - docker.addPanel( - 'processes', wcDocker.DOCK.STACKED, dashboardPanel); - }, - - save_current_layout: function(layout_id, docker) { - if(docker) { - let layout = docker.save(), - settings = { setting: layout_id, value: layout }; - - getApiInstance().post(url_for('settings.store_bulk'), settings); - } - }, - - restore_layout: function(docker, layout, defaultLayoutCallback, checkLayout= false) { - // Try to restore the layout if there is one - if (layout != '') { - try { - docker.restore(layout); - if(checkLayout) { - // Check restore layout is restored pgAdmin 4 layout successfully if not then reset layout to default pgAdmin 4 layout. - if((docker.findPanels('properties').length == 0 || docker.findPanels('browser').length == 0) && defaultLayoutCallback){ - // clear the wcDocker before reset layout. - docker.clear(); - Notify.info(gettext('pgAdmin has reset the layout because the previously saved layout is invalid.'), null); - defaultLayoutCallback(docker); - } - } - } - catch(err) { - docker.clear(); - if(defaultLayoutCallback) { - defaultLayoutCallback(docker); - } - } - } else { - if(defaultLayoutCallback) { - defaultLayoutCallback(docker); - } - } - - /* preference available only with top/opener browser. */ - let browser = pgWindow.pgAdmin.Browser; - - /* interval required initially as preference load may take time */ - let cacheIntervalId = setInterval(()=> { - let browserPref = browser.get_preferences_for_module('browser'); - if(browserPref) { - clearInterval(cacheIntervalId); - - browser.reflectLocklayoutChange(docker); - - browser.onPreferencesChange('browser', function() { - browser.reflectLocklayoutChange(docker); - }); - } - }, 5000); - }, - - reflectLocklayoutChange: function(docker) { - let browser = pgWindow.pgAdmin.Browser; - - let browserPref = browser.get_preferences_for_module('browser'); - browser.lock_layout(docker, browserPref.lock_layout); - }, - - lock_layout: function(docker, op) { - let menu_items = []; - if('mnu_locklayout' in this.all_menus_cache['file']) { - menu_items = this.all_menus_cache['file']['mnu_locklayout']['menu_items']; - } - - switch(op) { - case this.lock_layout_levels.PREVENT_DOCKING: - docker.lockLayout(wcDocker.LOCK_LAYOUT_LEVEL.PREVENT_DOCKING); - break; - case this.lock_layout_levels.FULL: - docker.lockLayout(wcDocker.LOCK_LAYOUT_LEVEL.FULL); - break; - case this.lock_layout_levels.NONE: - docker.lockLayout(wcDocker.LOCK_LAYOUT_LEVEL.NONE); - break; - } - - if(menu_items) { - _.each(menu_items, function(menu_item) { - if(menu_item.name != ('mnu_lock_'+op)) { - menu_item.change_checked(false); - } else { - menu_item.change_checked(true); - } - }); - } - }, - - save_lock_layout: function(op) { - let browser = pgWindow.pgAdmin.Browser; - - getApiInstance().put( - url_for('browser.lock_layout'), - JSON.stringify({ - 'value': op, - }) - ).then(()=> { - browser.cache_preferences('browser'); - }).catch(function(error) { - Notify.pgNotifier('error', error, gettext('Failed to save the lock layout setting.')); - }); - }, - - mnu_lock_docking: function() { - this.lock_layout(this.docker, this.lock_layout_levels.PREVENT_DOCKING); - this.save_lock_layout(this.lock_layout_levels.PREVENT_DOCKING); - }, - - mnu_lock_full: function() { - this.lock_layout(this.docker, this.lock_layout_levels.FULL); - this.save_lock_layout(this.lock_layout_levels.FULL); - }, - - mnu_lock_none: function() { - this.lock_layout(this.docker, this.lock_layout_levels.NONE); - this.save_lock_layout(this.lock_layout_levels.NONE); - }, -}); - -export {pgBrowser}; diff --git a/web/pgadmin/browser/static/js/node.js b/web/pgadmin/browser/static/js/node.js index 5742dedb7..b69b38965 100644 --- a/web/pgadmin/browser/static/js/node.js +++ b/web/pgadmin/browser/static/js/node.js @@ -7,12 +7,14 @@ // ////////////////////////////////////////////////////////////// -import {getNodeView, removeNodeView} from './node_view'; -import Notify from '../../../static/js/helpers/Notifier'; import _ from 'lodash'; import getApiInstance from '../../../static/js/api_instance'; -import { removePanelView } from './panel_view'; -import { TAB_CHANGE } from './constants'; +import { BROWSER_PANELS } from './constants'; +import React from 'react'; +import ObjectNodeProperties from '../../../misc/properties/ObjectNodeProperties'; +import ErrorBoundary from '../../../static/js/helpers/ErrorBoundary'; +import toPx from '../../../static/js/to_px'; +import usePreferences from '../../../preferences/static/js/store'; define('pgadmin.browser.node', [ 'sources/gettext', 'sources/pgadmin', @@ -21,9 +23,6 @@ define('pgadmin.browser.node', [ ], function( gettext, pgAdmin, generateUrl, commonUtils ) { - - let wcDocker = window.wcDocker; - const pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}; // It has already been defined. @@ -89,8 +88,11 @@ define('pgadmin.browser.node', [ dialogHelp: '', epasHelp: false, - title: function(o, d) { - return o.label + (d ? (' - ' + d.label) : ''); + title: function(d, action) { + if(action == 'create') { + return gettext('Create - %s', this.label); + } + return d.label??''; }, hasId: true, /////// @@ -282,114 +284,6 @@ define('pgadmin.browser.node', [ return true; } }, - addUtilityPanel: function(width, height, docker) { - let body = window.document.body, - el = document.createElement('div'), - dockerObject = docker || pgBrowser.docker; - - body.insertBefore(el, body.firstChild); - - let new_width = screen.width < 700 ? screen.width * 0.95 : screen.width * 0.5, - new_height = screen.height < 500 ? screen.height * 0.95 : screen.height * 0.4; - if (!_.isUndefined(width) && !_.isNull(width)) { - new_width = width; - } - if (!_.isUndefined(height) && !_.isNull(height)) { - new_height = height; - } - - let x = (body.offsetWidth - new_width) / 2; - let y = (body.offsetHeight - new_height) / 4; - - let new_panel = dockerObject.addPanel( - 'utility_props', window.wcDocker.DOCK.FLOAT, undefined, { - w: new_width, - h: new_height, - x: (x), - y: (y), - } - ); - /*set movable false to prevent dialog from docking, - by setting this we can able to move the dialog but can't dock it - in to the frame. e.g: can't dock it in to properties and other tabs. */ - setTimeout(function() { - new_panel.moveable(false); - }, 0); - - body.removeChild(el); - - return new_panel; - }, - - registerDockerPanel: function(docker, name, params) { - let w = docker || pgBrowser.docker, - p = w.findPanels(name); - - if (p && p.length == 1) - return; - - p = new pgBrowser.Panel({ - name: name, - showTitle: true, - isCloseable: true, - isPrivate: true, - isLayoutMember: false, - canMaximise: true, - content: '
', - ...params, - }); - p.load(w); - }, - registerUtilityPanel: function(docker) { - let w = docker || pgBrowser.docker, - p = w.findPanels('utility_props'); - - if (p && p.length == 1) - return; - - let events = {}; - - p = new pgBrowser.Panel({ - name: 'utility_props', - showTitle: true, - isCloseable: true, - isPrivate: true, - isLayoutMember: false, - canMaximise: true, - elContainer: true, - content: '
', - onCreate: function(myPanel, container) { - container.classList.add('pg-no-overflow'); - }, - events: events, - }); - p.load(w); - }, - register_node_panel: function() { - let w = pgBrowser.docker, - p = w.findPanels('node_props'); - - if (p && p.length == 1) - return; - - let events = {}; - - p = new pgBrowser.Panel({ - name: 'node_props', - showTitle: true, - isCloseable: true, - isPrivate: true, - isLayoutMember: false, - canMaximise: true, - elContainer: true, - content: '
', - onCreate: function(myPanel, container) { - container.classList.add('pg-no-overflow'); - }, - events: events, - }); - p.load(pgBrowser.docker); - }, /* * Default script type menu for node. * @@ -447,194 +341,132 @@ define('pgadmin.browser.node', [ **/ show_obj_properties: function(args, item) { let t = pgBrowser.tree, - i = (args && args.item) || item || t.selected(), - d = i ? t.itemData(i) : undefined, - o = this, - l = o.title.apply(this, [d]), - p; + nodeItem = (args && args.item) || item || t.selected(), + nodeData = nodeItem ? t.itemData(nodeItem) : undefined, + panelTitle = this.title(nodeData, args.action), + treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(nodeItem); - // Make sure - the properties dialog type registered - pgBrowser.Node.register_node_panel(); - - // No node selected. - if (!d) + if (!nodeData) return; - let self = this, - isParent = (_.isArray(this.parent_type) ? - function(_d) { - return (_.indexOf(self.parent_type, _d._type) != -1); - } : function(_d) { - return (self.parent_type == _d._type); - }), - addPanel = function() { - let body = window.document.body, - el = document.createElement('div'); - - body.insertBefore(el, body.firstChild); - - let w, h, x, y; - if(screen.width < 800) { - w = pgAdmin.toPx(el, '95%', 'width', true); - } else { - w = pgAdmin.toPx( - el, self.width || (pgBrowser.stdW.default + 'px'), - 'width', true - ); - - /* Fit to standard sizes */ - if(w <= pgBrowser.stdW.sm) { - w = pgBrowser.stdW.sm; - } else { - if(w <= pgBrowser.stdW.md) { - w = pgBrowser.stdW.md; - } else { - w = pgBrowser.stdW.lg; - } - } - } - - if(screen.height < 600) { - h = pgAdmin.toPx(el, '95%', 'height', true); - } else { - h = pgAdmin.toPx( - el, self.height || (pgBrowser.stdH.default + 'px'), - 'height', true - ); - - /* Fit to standard sizes */ - if(h <= pgBrowser.stdH.sm) { - h = pgBrowser.stdH.sm; - } else { - if(h <= pgBrowser.stdH.md) { - h = pgBrowser.stdH.md; - } else { - h = pgBrowser.stdH.lg; - } - } - } - - x = (body.offsetWidth - w) / 2; - y = (body.offsetHeight - h) / 4; - - // If the screen resolution is higher, but - it is zoomed, dialog - // may be go out of window, and will not be accessible through the - // keyboard. - if (w > window.innerWidth) { - x = 0; - w = window.innerWidth; - } - if (h > window.innerHeight) { - y = 0; - h = window.innerHeight; - } - - let new_panel = pgBrowser.docker.addPanel( - 'node_props', wcDocker.DOCK.FLOAT, undefined, { - w: w + 'px', - h: h + 'px', - x: x + 'px', - y: y + 'px', - } - ); - - body.removeChild(el); - - return new_panel; - }; + const isParent = (_.isArray(this.parent_type) ? + (_d)=>{ + return (_.indexOf(this.parent_type, _d._type) != -1); + } : (_d)=>{ + return (this.parent_type == _d._type); + }); if (args.action == 'create') { // If we've parent, we will get the information of it for // proper object manipulation. - // - // You know - we're working with RDBMS, relation is everything - // for us. - if (self.parent_type && !isParent(d)) { - // In browser tree, I can be under any node, But - that - // does not mean, it is my parent. - // - // We have some group nodes too. - // - // i.e. - // Tables, Views, etc. nodes under Schema node - // - // And, actual parent of a table is schema, not Tables. - while (i && t.hasParent(i)) { - i = t.parent(i); - let pd = t.itemData(i); + if (this.parent_type && !isParent(nodeData)) { + // actual parent of a table is schema, not Tables. + while (nodeItem && t.hasParent(nodeItem)) { + nodeItem = t.parent(nodeItem); + let pd = t.itemData(nodeItem); if (isParent(pd)) { // Assign the data, this is my actual parent. - d = pd; + nodeData = pd; break; } } } - // Seriously - I really don't have parent data present? - // - // The only node - which I know - who does not have parent - // node, is the Server Group (and, comes directly under root - // node - which has no parent.) - if (!d || (this.parent_type != null && !isParent(d))) { + // The only node who does not have parent is the Server Group + if (!nodeData || (this.parent_type != null && !isParent(nodeData))) { // It should never come here. // If it is here, that means - we do have some bug in code. return; } - l = gettext('Create - %s', this.label); - if (this.type == 'server') { - l = gettext('Register - %s', this.label); - } - p = addPanel(); - - setTimeout(function() { - o.showProperties(i, d, p, args.action); - }, 10); - } else { - if (pgBrowser.Node.panels && pgBrowser.Node.panels[d.id] && - pgBrowser.Node.panels[d.id].$container) { - p = pgBrowser.Node.panels[d.id]; - /** TODO :: - * Run in edit mode (if asked) only when it is - * not already been running edit mode - **/ - let mode = p.$container.attr('action-mode'); - if (mode) { - let msg = gettext('Are you sure want to stop editing the properties of %s "%s"?'); - if (args.action == 'edit') { - msg = gettext('Are you sure want to reset the current changes and re-open the panel for %s "%s"?'); - } - - Notify.confirm( - gettext('Edit in progress?'), - commonUtils.sprintf(msg, o.label.toLowerCase(), d.label), - function() { - setTimeout(function() { - o.showProperties(i, d, p, args.action); - }, 10); - }, - null).show(); - } else { - setTimeout(function() { - o.showProperties(i, d, p, args.action); - }, 10); + const panelId = _.uniqueId(BROWSER_PANELS.EDIT_PROPERTIES); + const onClose = (force=false)=>pgBrowser.docker.close(panelId, force); + const onSave = (newNodeData)=>{ + // Clear the cache for this node now. + setTimeout(()=>{ + this.clear_cache.apply(this, item); + }, 0); + try { + pgBrowser.Events.trigger( + 'pgadmin:browser:tree:add', _.clone(newNodeData.node), + _.clone(treeNodeInfo) + ); + } catch (e) { + console.warn(e.stack || e); } - } else { - pgBrowser.Node.panels = pgBrowser.Node.panels || {}; - p = pgBrowser.Node.panels[d.id] = addPanel(); + onClose(); + }; + this.showPropertiesDialog(panelId, panelTitle, { + treeNodeInfo: treeNodeInfo, + item: nodeItem, + nodeData: nodeData, + actionType: 'create', + onSave: onSave, + onClose: onClose, + }); + } else { + const panelId = BROWSER_PANELS.EDIT_PROPERTIES+nodeData.id; + const onClose = (force=false)=>pgBrowser.docker.close(panelId, force); + const onSave = (newNodeData)=>{ + let _old = nodeData, + _new = newNodeData.node, + info = treeNodeInfo; - setTimeout(function() { - o.showProperties(i, d, p, args.action); - }, 10); + // Clear the cache for this node now. + setTimeout(()=>{ + this.clear_cache.apply(this, item); + }, 0); + + pgBrowser.Events.trigger( + 'pgadmin:browser:tree:update', + _old, _new, info, { + success: function(_item, _newNodeData, _oldNodeData) { + pgBrowser.Events.trigger( + 'pgadmin:browser:node:updated', _item, _newNodeData, + _oldNodeData + ); + pgBrowser.Events.trigger( + 'pgadmin:browser:node:' + _newNodeData._type + ':updated', + _item, _newNodeData, _oldNodeData + ); + }, + } + ); + onClose(); + }; + if(pgBrowser.docker.find(panelId)) { + let msg = gettext('Are you sure want to stop editing the properties of %s "%s"?'); + if (args.action == 'edit') { + msg = gettext('Are you sure want to reset the current changes and re-open the panel for %s "%s"?'); + } + + pgAdmin.Browser.notifier.confirm( + gettext('Edit in progress?'), + commonUtils.sprintf(msg, this.label.toLowerCase(), nodeData.label), + ()=>{ + this.showPropertiesDialog(panelId, panelTitle, { + treeNodeInfo: treeNodeInfo, + item: nodeItem, + nodeData: nodeData, + actionType: 'edit', + onSave: onSave, + onClose: onClose, + }, true); + }, + null + ); + } else { + this.showPropertiesDialog(panelId, panelTitle, { + treeNodeInfo: treeNodeInfo, + item: nodeItem, + nodeData: nodeData, + actionType: 'edit', + onSave: onSave, + onClose: onClose, + }); } } - - p.title(l); - p.icon('icon-' + this.type); - - // Make sure the properties dialog is visible - p.focus(); }, // Delete the selected object delete_obj: function(args, item) { @@ -668,7 +500,7 @@ define('pgadmin.browser.node', [ if (!(_.isFunction(obj.canDropCascade) ? obj.canDropCascade.apply(obj, [d, i]) : obj.canDropCascade)) { - Notify.error( + pgAdmin.Browser.notifier.error( gettext('The %s "%s" cannot be dropped.', obj.label, d.label), 10000 ); @@ -685,24 +517,24 @@ define('pgadmin.browser.node', [ if (!(_.isFunction(obj.canDrop) ? obj.canDrop.apply(obj, [d, i]) : obj.canDrop)) { - Notify.error( + pgAdmin.Browser.notifier.error( gettext('The %s "%s" cannot be dropped/removed.', obj.label, d.label), 10000 ); return; } } - Notify.confirm(title, msg, + pgAdmin.Browser.notifier.confirm(title, msg, function() { getApiInstance().delete( obj.generate_url(i, input.url, d, true), ).then(({data: res})=> { if(res.success == 2){ - Notify.error(res.info, null); + pgAdmin.Browser.notifier.error(res.info, null); return; } if (res.success == 0) { - Notify.alert(res.errormsg, res.info); + pgAdmin.Browser.notifier.alert(res.errormsg, res.info); } else { // Remove the node from tree and set collection node as selected. let selectNextNode = true; @@ -727,7 +559,7 @@ define('pgadmin.browser.node', [ console.warn(e.stack || e); } } - Notify.alert(gettext('Error dropping/removing %s: "%s"', obj.label, objName), errmsg); + pgAdmin.Browser.notifier.alert(gettext('Error dropping/removing %s: "%s"', obj.label, objName), errmsg); }); } ); @@ -773,7 +605,7 @@ define('pgadmin.browser.node', [ // Callback to render query editor show_query_tool: function(args, item) { - let preference = pgBrowser.get_preference('sqleditor', 'copy_sql_to_query_tool'); + let preference = usePreferences.getState().getPreferences('sqleditor', 'copy_sql_to_query_tool'); let t = pgBrowser.tree, i = item || t.selected(), d = i ? t.itemData(i) : undefined; @@ -862,7 +694,7 @@ define('pgadmin.browser.node', [ pgBrowser.Node.callbacks.change_server_background(item, data); }, // Callback called - when a node is selected in browser tree. - selected: function(item, data, browser, _argsList, _event, actionSource) { + selected: function(item, data, browser) { // Show the information about the selected node in the below panels, // which are visible at this time: // + Properties @@ -870,34 +702,11 @@ define('pgadmin.browser.node', [ // + Dependents // + Dependencies // + Statistics - let b = browser || pgBrowser, - t = b.tree, - d = data || t.itemData(item); + let b = browser || pgBrowser; // Update the menu items pgAdmin.Browser.enable_disable_menus.apply(b, [item]); - if (d && b) { - - if ('properties' in b.panels && - b.panels['properties'] && - b.panels['properties'].panel) { - - if (actionSource != TAB_CHANGE) { - const propertiesPanel = b.panels['properties'].panel.$container.find('.obj_properties').first(); - if (propertiesPanel) { - removePanelView(propertiesPanel[0]); - } - } - - if (b.panels['properties'].panel.isVisible()) { - this.showProperties(item, d, b.panels['properties'].panel); - } - - } - - } - pgBrowser.Events.trigger('pgadmin:browser:tree:update-tree-state', item); return true; @@ -922,7 +731,7 @@ define('pgadmin.browser.node', [ }, opened: function(item) { let tree = pgBrowser.tree, - auto_expand = pgBrowser.get_preference('browser', 'auto_expand_sole_children'); + auto_expand = usePreferences.getState().getPreferences('browser', 'auto_expand_sole_children'); if (auto_expand && auto_expand.value && tree.children(item).length == 1) { // Automatically expand the child node, if a treeview node has only a single child. @@ -957,127 +766,55 @@ define('pgadmin.browser.node', [ item); }, }, - /********************************************************************** - * A hook (not a callback) to show object properties in given HTML - * element. - * - * This has been used for the showing, editing properties of the node. - * This has also been used for creating a node. - **/ - showProperties: function(item, data, panel, action) { - let that = this, - j = panel.$container.find('.obj_properties').first(); + showPropertiesDialog: function(panelId, panelTitle, dialogProps, update=false) { + const panelData = { + id: panelId, + title: panelTitle, + manualClose: true, + icon: `dialog-node-icon ${this.node_image?.(dialogProps.itemNodeData) ?? ('icon-' + this.type)}`, + content: ( + + + + ) + }; - // Callback to show object properties - let properties = function() { - let treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(item); - getNodeView( - that.type, treeNodeInfo, 'properties', data, 'tab', j[0], this, onEdit - ); - return; - }.bind(panel), + let w = toPx(this.width || (pgBrowser.stdW.default + 'px'), 'width', true); + let h = toPx(this.height || (pgBrowser.stdH.default + 'px'), 'height', true); - editFunc = function() { - let self = this; - if (action && action == 'properties') { - action = 'edit'; - } - self.$container.attr('action-mode', action); - - self.icon( - _.isFunction(that['node_image']) ? - (that['node_image']).apply(that, [data]) : - (that['node_image'] || ('icon-' + that.type)) - ); - /* Remove any dom rendered by getNodeView */ - removeNodeView(j[0]); - /* getSchema is a schema for React. Get the react node view */ - let treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(item); - getNodeView( - that.type, treeNodeInfo, action, data, 'dialog', j[0], this, onEdit, - (nodeData)=>{ - if(nodeData.node) { - onSaveFunc(nodeData.node, treeNodeInfo); - if(nodeData.success === 0) { - Notify.alert(gettext('Error'), - gettext(nodeData.errormsg) - ); - } - } - } - ); - return; - - }.bind(panel), - - updateTreeItem = function(obj, tnode, node_info) { - let _old = data, - _new = tnode, - info = node_info; - - // Clear the cache for this node now. - setTimeout(function() { - obj.clear_cache.apply(obj, item); - }, 0); - - pgBrowser.Events.trigger( - 'pgadmin:browser:tree:update', - _old, _new, info, { - success: function(_item, _newNodeData, _oldNodeData) { - pgBrowser.Events.trigger( - 'pgadmin:browser:node:updated', _item, _newNodeData, - _oldNodeData - ); - pgBrowser.Events.trigger( - 'pgadmin:browser:node:' + _newNodeData._type + ':updated', - _item, _newNodeData, _oldNodeData - ); - }, - } - ); - this.close(); - }, - saveNewNode = function(obj, tnode, node_info) { - // Clear the cache for this node now. - setTimeout(function() { - obj.clear_cache.apply(obj, item); - }, 0); - try { - pgBrowser.Events.trigger( - 'pgadmin:browser:tree:add', _.clone(tnode), - _.clone(node_info) - ); - } catch (e) { - console.warn(e.stack || e); - } - this.close(); - }.bind(panel, that), - editInNewPanel = function() { - // Open edit in separate panel - setTimeout(function() { - that.callbacks.show_obj_properties.apply(that, [{ - 'action': 'edit', - 'item': item, - }]); - }, 0); - }, - onSaveFunc = updateTreeItem.bind(panel, that), - onEdit = editFunc.bind(panel); - - if (action) { - if (action == 'create') { - onSaveFunc = saveNewNode; - } - if (action != 'properties') { - // We need to keep track edit/create mode for this panel. - editFunc(); - } else { - properties(); - } + /* Fit to standard sizes */ + if(w <= pgBrowser.stdW.sm) { + w = pgBrowser.stdW.sm; } else { - /* Show properties */ - onEdit = editInNewPanel.bind(panel); - properties(); + if(w <= pgBrowser.stdW.md) { + w = pgBrowser.stdW.md; + } else { + w = pgBrowser.stdW.lg; + } + } + + if(h <= pgBrowser.stdH.sm) { + h = pgBrowser.stdH.sm; + } else { + if(h <= pgBrowser.stdH.md) { + h = pgBrowser.stdH.md; + } else { + h = pgBrowser.stdH.lg; + } + } + + if(update) { + dialogProps.onClose(true); + setTimeout(()=>{ + pgBrowser.docker.openDialog(panelData, w, h); + }, 10); + } else { + pgBrowser.docker.openDialog(panelData, w, h); } }, _find_parent_node: function(t, i, d) { diff --git a/web/pgadmin/browser/static/js/node_view.jsx b/web/pgadmin/browser/static/js/node_view.jsx deleted file mode 100644 index 9dded4d1a..000000000 --- a/web/pgadmin/browser/static/js/node_view.jsx +++ /dev/null @@ -1,225 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2023, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// - -import React from 'react'; -import ReactDOM from 'react-dom'; - -import pgAdmin from 'sources/pgadmin'; -import getApiInstance from 'sources/api_instance'; -import {getHelpUrl, getEPASHelpUrl} from 'pgadmin.help'; -import SchemaView from 'sources/SchemaView'; -import { generateNodeUrl } from './node_ajax'; -import Notify from '../../../static/js/helpers/Notifier'; -import gettext from 'sources/gettext'; -import 'wcdocker'; -import Theme from '../../../static/js/Theme'; - -/* The entry point for rendering React based view in properties, called in node.js */ -export function getNodeView(nodeType, treeNodeInfo, actionType, itemNodeData, formType, container, containerPanel, onEdit, onSave) { - let nodeObj = pgAdmin.Browser.Nodes[nodeType]; - let serverInfo = treeNodeInfo && ('server' in treeNodeInfo) && - pgAdmin.Browser.serverInfo && pgAdmin.Browser.serverInfo[treeNodeInfo.server._id]; - let inCatalog = treeNodeInfo && ('catalog' in treeNodeInfo); - let urlBase = generateNodeUrl.call(nodeObj, treeNodeInfo, actionType, itemNodeData, false, nodeObj.url_jump_after_node); - const api = getApiInstance(); - const url = (isNew)=>{ - return urlBase + (isNew ? '' : itemNodeData._id); - }; - let isDirty = false; // usefull for warnings - let warnOnCloseFlag = true; - const confirmOnCloseReset = pgAdmin.Browser.get_preferences_for_module('browser').confirm_on_properties_close; - let updatedData = ['table', 'partition'].includes(nodeType) && !_.isEmpty(itemNodeData.rows_cnt) ? {rows_cnt: itemNodeData.rows_cnt} : undefined; - - let onError = (err)=> { - if(err.response){ - console.error('error resp', err.response); - } else if(err.request){ - console.error('error req', err.request); - } else if(err.message){ - console.error('error msg', err.message); - } - }; - - /* Called when dialog is opened in edit mode, promise required */ - let initData = ()=>new Promise((resolve, reject)=>{ - if(actionType === 'create') { - resolve({}); - } else { - api.get(url(false)) - .then((res)=>{ - resolve(res.data); - }) - .catch((err)=>{ - Notify.pgNotifier('error', err, '', function(msg) { - if (msg == 'CRYPTKEY_SET') { - return Promise.resolve(initData()); - } else if (msg == 'CRYPTKEY_NOT_SET') { - reject(gettext('The master password is not set.')); - } - reject(err); - }); - }); - } - }); - - /* on save button callback, promise required */ - const onSaveClick = (isNew, data)=>new Promise((resolve, reject)=>{ - return api({ - url: url(isNew), - method: isNew ? 'POST' : 'PUT', - data: data, - }).then((res)=>{ - /* Don't warn the user before closing dialog */ - warnOnCloseFlag = false; - resolve(res.data); - onSave && onSave(res.data); - }).catch((err)=>{ - Notify.pgNotifier('error-noalert', err, '', function(msg) { - if (msg == 'CRYPTKEY_SET') { - return Promise.resolve(onSaveClick(isNew, data)); - } else if (msg == 'CRYPTKEY_NOT_SET') { - reject(gettext('The master password is not set.')); - } - reject(err); - }); - }); - }); - - /* Called when switched to SQL tab, promise required */ - const getSQLValue = (isNew, changedData)=>{ - const msqlUrl = generateNodeUrl.call(nodeObj, treeNodeInfo, 'msql', itemNodeData, !isNew, nodeObj.url_jump_after_node); - return new Promise((resolve, reject)=>{ - api({ - url: msqlUrl, - method: 'GET', - params: changedData, - }).then((res)=>{ - resolve(res.data.data); - }).catch((err)=>{ - onError(err); - reject(err); - }); - }); - }; - - /* Callback for help button */ - const onHelp = (isSqlHelp=false, isNew=false)=>{ - if(isSqlHelp) { - let server = treeNodeInfo.server; - let helpUrl = pgAdmin.Browser.utils.pg_help_path; - let fullUrl = ''; - - if (server.server_type == 'ppas' && nodeObj.epasHelp) { - fullUrl = getEPASHelpUrl(server.version); - } else { - if (nodeObj.sqlCreateHelp == '' && nodeObj.sqlAlterHelp != '') { - fullUrl = getHelpUrl(helpUrl, nodeObj.sqlAlterHelp, server.version); - } else if (nodeObj.sqlCreateHelp != '' && nodeObj.sqlAlterHelp == '') { - fullUrl = getHelpUrl(helpUrl, nodeObj.sqlCreateHelp, server.version); - } else { - if (isNew) { - fullUrl = getHelpUrl(helpUrl, nodeObj.sqlCreateHelp, server.version); - } else { - fullUrl = getHelpUrl(helpUrl, nodeObj.sqlAlterHelp, server.version); - } - } - } - - window.open(fullUrl, 'postgres_help'); - } else { - window.open(nodeObj.dialogHelp, 'pgadmin_help'); - } - }; - - /* A warning before closing the dialog with unsaved changes, based on preference */ - let warnBeforeChangesLost = (yesCallback)=>{ - let confirmOnClose = pgAdmin.Browser.get_preferences_for_module('browser').confirm_on_properties_close; - if (warnOnCloseFlag && confirmOnClose) { - if(isDirty){ - Notify.confirm( - gettext('Warning'), - gettext('Changes will be lost. Are you sure you want to close the dialog?'), - function() { - yesCallback(); - return true; - }, - function() { - return true; - } - ); - } else { - return true; - } - return false; - } else { - yesCallback(); - return true; - } - }; - - /* Bind the wcDocker dialog close event and check if user should be warned */ - if (containerPanel.closeable()) { - containerPanel.on(window.wcDocker.EVENT.CLOSING, warnBeforeChangesLost.bind( - containerPanel, - function() { - containerPanel.off(window.wcDocker.EVENT.CLOSING); - /* Always clean up the react mounted dom before closing */ - removeNodeView(container); - containerPanel.close(); - } - )); - } - - /* All other useful details can go with this object */ - const viewHelperProps = { - mode: actionType, - serverInfo: serverInfo ? { - type: serverInfo.server_type, - version: serverInfo.version, - }: undefined, - inCatalog: inCatalog, - }; - - let schema = nodeObj.getSchema.call(nodeObj, treeNodeInfo, itemNodeData); - // Show/Hide security group for nodes under the catalog - if('catalog' in treeNodeInfo - && formType !== 'tab') { - schema.filterGroups = [gettext('Security')]; - } - - /* Fire at will, mount the DOM */ - ReactDOM.render( - - containerPanel.close()} - onHelp={onHelp} - onEdit={onEdit} - onDataChange={(dataChanged)=>{ - isDirty = dataChanged; - }} - confirmOnCloseReset={confirmOnCloseReset} - hasSQL={nodeObj.hasSQL && (actionType === 'create' || actionType === 'edit')} - getSQLValue={getSQLValue} - disableSqlHelp={nodeObj.sqlAlterHelp == '' && nodeObj.sqlCreateHelp == '' && !nodeObj.epasHelp} - disableDialogHelp={nodeObj.dialogHelp == undefined || nodeObj.dialogHelp == ''} - /> - , container); -} - -/* When switching from normal node to collection node, clean up the React mounted DOM */ -export function removeNodeView(container) { - ReactDOM.unmountComponentAtNode(container); -} diff --git a/web/pgadmin/browser/static/js/panel.js b/web/pgadmin/browser/static/js/panel.js deleted file mode 100644 index fdbce815f..000000000 --- a/web/pgadmin/browser/static/js/panel.js +++ /dev/null @@ -1,290 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2023, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// - -import { getPanelView } from './panel_view'; -import _ from 'lodash'; - -define( - ['sources/pgadmin', 'wcdocker'], - function(pgAdmin) { - - let pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}, - wcDocker = window.wcDocker; - - pgAdmin.Browser.Panel = function(options) { - let defaults = [ - 'name', 'title', 'width', 'height', 'showTitle', 'isCloseable', - 'isPrivate', 'isLayoutMember', 'content', 'icon', 'events', 'onCreate', 'elContainer', - 'canHide', 'limit', 'extraClasses', 'canMaximise', - ]; - _.extend(this, _.pick(options, defaults)); - }; - - _.extend(pgAdmin.Browser.Panel.prototype, { - name: '', - title: '', - width: 300, - height: 600, - showTitle: true, - isCloseable: true, - isPrivate: false, - isLayoutMember: true, - content: '', - icon: '', - panel: null, - onCreate: null, - elContainer: false, - canMaximise: false, - limit: null, - extraClasses: null, - load: function(docker, title) { - let that = this; - if (!that.panel) { - docker.registerPanelType(that.name, { - title: that.title, - isPrivate: that.isPrivate, - limit: that.limit, - isLayoutMember: that.isLayoutMember, - onCreate: function(myPanel) { - myPanel.panelData = { - pgAdminName: that.name, - }; - myPanel.initSize(that.width, that.height); - - if (!that.showTitle) - myPanel.title(false); - else { - let title_elem = '' + (title || that.title) + ''; - myPanel.title(title_elem); - if (that.icon != '') - myPanel.icon(that.icon); - } - - let container = document.createElement('div'); - container.setAttribute('class', 'pg-panel-content'); - container.innerHTML = that.content; - - // Add extra classes - if (!_.isNull('extraClasses')) { - container.classList.add(that.extraClasses); - } - - myPanel.maximisable(!!that.canMaximise); - myPanel.closeable(!!that.isCloseable); - myPanel.layout().addItem(container); - that.panel = myPanel; - if (that.events && _.isObject(that.events)) { - _.each(that.events, function(v, k) { - if (v && _.isFunction(v)) { - myPanel.on(k, v); - } - }); - } - _.each([ - wcDocker.EVENT.UPDATED, wcDocker.EVENT.VISIBILITY_CHANGED, - wcDocker.EVENT.BEGIN_DOCK, wcDocker.EVENT.END_DOCK, - wcDocker.EVENT.GAIN_FOCUS, wcDocker.EVENT.LOST_FOCUS, - wcDocker.EVENT.CLOSED, wcDocker.EVENT.BUTTON, - wcDocker.EVENT.ATTACHED, wcDocker.EVENT.DETACHED, - wcDocker.EVENT.MOVE_STARTED, wcDocker.EVENT.MOVE_ENDED, - wcDocker.EVENT.MOVED, wcDocker.EVENT.RESIZE_STARTED, - wcDocker.EVENT.RESIZE_ENDED, wcDocker.EVENT.RESIZED, - wcDocker.EVENT.SCROLLED, - ], function(ev) { - myPanel.on(ev, that.eventFunc.bind(myPanel, ev)); - }); - - if (that.onCreate && _.isFunction(that.onCreate)) { - that.onCreate.apply(that, [myPanel, container]); - } - - // Prevent browser from opening the drag file. - // Using addEventListener to avoid conflict with jquery.drag - ['dragover', 'drop'].forEach((eventName)=>{ - container.addEventListener(eventName, function(event) { - event.stopPropagation(); - event.preventDefault(); - }); - }); - - if (that.elContainer) { - myPanel.pgElContainer = container; - _.each([ - wcDocker.EVENT.RESIZED, wcDocker.EVENT.ATTACHED, - wcDocker.EVENT.DETACHED, wcDocker.EVENT.VISIBILITY_CHANGED, - ], function(ev) { - myPanel.on(ev, that.resizedContainer.bind(myPanel)); - }); - that.resizedContainer.apply(myPanel); - } - - if (myPanel._type == 'dashboard' || myPanel._type == 'processes') { - getPanelView( - pgBrowser.tree, - container, - pgBrowser, - myPanel._type - ); - } - - // Re-render the dashboard panel when preference value 'show graph' gets changed. - pgBrowser.onPreferencesChange('dashboards', function() { - getPanelView( - pgBrowser.tree, - container, - pgBrowser, - myPanel._type - ); - }); - - // Re-render the dashboard panel when preference value gets changed. - pgBrowser.onPreferencesChange('graphs', function() { - getPanelView( - pgBrowser.tree, - container, - pgBrowser, - myPanel._type - ); - }); - - _.each([wcDocker.EVENT.CLOSED, wcDocker.EVENT.VISIBILITY_CHANGED], - function(ev) { - myPanel.on(ev, that.handleVisibility.bind(myPanel, ev)); - }); - - pgBrowser.Events.on('pgadmin-browser:tree:selected', () => { - - if(myPanel.isVisible() && myPanel._type !== 'properties') { - getPanelView( - pgBrowser.tree, - container, - pgBrowser, - myPanel._type - ); - } - }); - - pgBrowser.Events.on('pgadmin:database:connected', () => { - - if(myPanel.isVisible() && myPanel._type !== 'properties') { - getPanelView( - pgBrowser.tree, - container, - pgBrowser, - myPanel._type - ); - } - }); - - pgBrowser.Events.on('pgadmin-browser:tree:refreshing', () => { - - if(myPanel.isVisible() && myPanel._type !== 'properties') { - getPanelView( - pgBrowser.tree, - container, - pgBrowser, - myPanel._type - ); - } - }); - }, - }); - } - }, - eventFunc: function(eventName) { - let name = this.panelData.pgAdminName; - try { - pgBrowser.Events.trigger( - 'pgadmin-browser:panel', eventName, this, arguments - ); - pgBrowser.Events.trigger( - 'pgadmin-browser:panel:' + eventName, this, arguments - ); - - if (name) { - pgBrowser.Events.trigger( - 'pgadmin-browser:panel-' + name, eventName, this, arguments - ); - pgBrowser.Events.trigger( - 'pgadmin-browser:panel-' + name + ':' + eventName, this, arguments - ); - } - } catch (e) { - console.warn(e.stack || e); - } - }, - resizedContainer: function() { - let p = this; - - if (p.pgElContainer && !p.pgResizeTimeout) { - if (!p.isVisible()) { - clearTimeout(p.pgResizeTimeout); - p.pgResizeTimeout = null; - - return; - } - p.pgResizeTimeout = setTimeout( - function() { - let w = p.width(), - elAttr = 'xs'; - p.pgResizeTimeout = null; - - /** Calculations based on https://getbootstrap.com/docs/4.1/layout/grid/#grid-options **/ - if (w >= 480) { - elAttr = 'sm'; - } - if (w >= 768) { - elAttr = 'md'; - } - if (w >= 992) { - elAttr = 'lg'; - } - if (w >=1200) { - elAttr = 'xl'; - } - - p.pgElContainer.setAttribute('el', elAttr); - }, - 100 - ); - } - }, - handleVisibility: function(eventName) { - let selectedPanel = pgBrowser.docker.findPanels(this._type)[0]; - let isPanelVisible = selectedPanel.isVisible(); - let container = selectedPanel - .layout() - .scene() - .find('.pg-panel-content'); - - if (isPanelVisible && ['dashboard', 'statistics', 'dependencies', 'dependents', 'sql', 'processes'].includes(selectedPanel._type) ) { - if (eventName == 'panelVisibilityChanged') { - getPanelView( - pgBrowser.tree, - container[0], - pgBrowser, - this._type - ); - } - } - if (eventName == 'panelClosed' && selectedPanel._type == 'dashboard') { - getPanelView( - pgBrowser.tree, - container[0], - pgBrowser, - this._type, - false - ); - } - } - - }); - - return pgAdmin.Browser.Panel; - }); diff --git a/web/pgadmin/browser/static/js/panel_view.jsx b/web/pgadmin/browser/static/js/panel_view.jsx deleted file mode 100644 index 4e271c30d..000000000 --- a/web/pgadmin/browser/static/js/panel_view.jsx +++ /dev/null @@ -1,148 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2023, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// - -import React from 'react'; -import ReactDOM from 'react-dom'; -import Theme from 'sources/Theme'; -import Dependencies from '../../../misc/dependencies/static/js/Dependencies'; -import Dependents from '../../../misc/dependents/static/js/Dependents'; -import Statistics from '../../../misc/statistics/static/js/Statistics'; -import SQL from '../../../misc/sql/static/js/SQL'; -import Dashboard from '../../../dashboard/static/js/Dashboard'; -import _ from 'lodash'; -import { CollectionNodeView } from '../../../misc/properties/CollectionNodeProperties'; -import Processes from '../../../misc/bgprocess/static/js/Processes'; - - -/* The entry point for rendering React based view in properties, called in node.js */ -export function getPanelView( - tree, - container, - pgBrowser, - panelType, - panelVisible = true -) { - let item = !_.isNull(tree)? tree.selected(): null, - nodeData, node, treeNodeInfo, preferences, graphPref, dashPref; - - if (item){ - nodeData = tree.itemData(item); - node = nodeData && pgBrowser.Nodes[nodeData._type]; - treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(item); - dashPref = pgBrowser.get_preferences_for_module('dashboards'); - graphPref = pgBrowser.get_preferences_for_module('graphs'); - preferences = _.merge(dashPref, graphPref); - - } - if (panelType == 'dashboard') { - ReactDOM.render( - - - , - container - ); - } - if (panelType == 'statistics') { - ReactDOM.render( - - - , - container - ); - } - if (panelType == 'properties' && nodeData?.is_collection) { - ReactDOM.render( - - - , - container - ); - } - if (panelType == 'dependencies') { - ReactDOM.render( - - - , - container - ); - } - if (panelType == 'dependents') { - ReactDOM.render( - - - , - container - ); - } - if (panelType == 'sql') { - ReactDOM.render( - - - , - container - ); - } - if (panelType == 'processes') { - ReactDOM.render( - - - , - container - ); - } -} - -/* When switching from normal node to collection node, clean up the React mounted DOM */ -export function removePanelView(container) { - ReactDOM.unmountComponentAtNode(container); -} diff --git a/web/pgadmin/browser/static/js/preferences.js b/web/pgadmin/browser/static/js/preferences.js deleted file mode 100644 index 028187bba..000000000 --- a/web/pgadmin/browser/static/js/preferences.js +++ /dev/null @@ -1,148 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2023, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// - -import pgAdmin from 'sources/pgadmin'; -import url_for from 'sources/url_for'; -import Notify from '../../../static/js/helpers/Notifier'; -import { shortcutToString } from '../../../static/js/components/ShortcutTitle'; -import gettext from 'sources/gettext'; -import getApiInstance from '../../../static/js/api_instance'; - - -const pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}; - -/* Add cache related methods and properties */ -_.extend(pgBrowser, { - /* This will hold preference data (Works as a cache object) - * Here node will be a key and it's preference data will be value - */ - preferences_cache: [], - - /* This will be used by poller of new tabs/windows to check - * if preference cache is updated in parent/window.opener. - */ - prefcache_version: 0, - - /* Generate a unique version number */ - generate_preference_version: function() { - return (new Date()).getTime(); - }, - - preference_version: function(version) { - if(version) { - this.prefcache_version = version; - } - else { - return this.prefcache_version; - } - }, - - /* Get cached preference */ - get_preference: function(module, preference){ - const self = this; - - return _.find( - self.preferences_cache, {'module': module, 'name': preference} - ); - }, - - /* Get all the preferences of a module */ - get_preferences_for_module: function(module) { - let self = this; - let preferences = {}; - _.forEach( - _.filter(self.preferences_cache, {'module': module}), - (preference) => { - preferences[preference.name] = preference.value; - } - ); - if(Object.keys(preferences).length > 0) { - return preferences; - } - }, - - /* Get preference of an id, id is numeric */ - get_preference_for_id : function(id) { - let self = this; - /* find returns undefined if not found */ - return _.find(self.preferences_cache, {'id': id}); - }, - - // Get and cache the preferences - cache_preferences: function (modulesChanged) { - let self = this; - - setTimeout(function() { - getApiInstance().get(url_for('preferences.get_all')) - .then(({data: res})=>{ - self.preferences_cache = res; - self.preference_version(self.generate_preference_version()); - - pgBrowser.keyboardNavigation.init(); - - // Initialize Tree saving/reloading - pgBrowser.browserTreeState.init(); - - /* Once the cache is loaded after changing the preferences, - * notify the modules of the change - */ - if(modulesChanged) { - if(typeof modulesChanged === 'string'){ - pgBrowser.Events.trigger('prefchange:'+modulesChanged); - } else { - _.each(modulesChanged, (val, key)=> { - pgBrowser.Events.trigger('prefchange:'+key); - }); - } - } - }) - .catch(function(error) { - Notify.pgRespErrorNotify(error); - }); - }, 500); - }, - - triggerPreferencesChange: function(moduleChanged) { - pgBrowser.Events.trigger('prefchange:'+moduleChanged); - }, - - reflectPreferences: function(module) { - let obj = this; - //browser preference - if(module === 'browser') { - let browserPreferences = obj.get_preferences_for_module('browser'); - let buttonList = obj?.panels?.browser?.panel?._buttonList; - buttonList.forEach(btn => { - let key = null; - switch(btn.name) { - case gettext('Query Tool'): - key = shortcutToString(browserPreferences.sub_menu_query_tool,null,true); - obj?.panels?.browser?.panel?.updateButton(gettext('Query Tool'), {key}); - break; - case gettext('View Data'): - key = shortcutToString(browserPreferences.sub_menu_view_data,null,true); - obj?.panels?.browser?.panel?.updateButton(gettext('View Data'), {key}); - break; - case gettext('Search objects'): - key = shortcutToString(browserPreferences.sub_menu_search_objects,null,true); - obj?.panels?.browser?.panel?.updateButton(gettext('Search objects'), {key}); - } - }); - } - }, - - onPreferencesChange: function(module, eventHandler) { - pgBrowser.Events?.on('prefchange:'+module, function(event) { - eventHandler(event); - }); - }, - -}); - -export {pgBrowser}; diff --git a/web/pgadmin/browser/static/js/quick_search/iframe_component.js b/web/pgadmin/browser/static/js/quick_search/iframe_component.js deleted file mode 100644 index 6c48bc759..000000000 --- a/web/pgadmin/browser/static/js/quick_search/iframe_component.js +++ /dev/null @@ -1,44 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2023, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// - -import React, {Component} from 'react'; -import PropTypes from 'prop-types'; - -// Allow us to render IFrame using React -// Here we will add the event listener on Iframe load event -export class Iframe extends Component { - static get propTypes() { - return { - id: PropTypes.string.isRequired, - srcURL: PropTypes.string.isRequired, - onLoad: PropTypes.func.isRequired, - }; - } - - render () { - const iframeStyle = { - border: '0', - display: 'block', - position:'absolute', - opacity:'0', - }; - const {id, srcURL, onLoad} = this.props; - - return ( -