.babelrc000066400000000000000000000003501520131260200124370ustar00rootroot00000000000000{ "presets": [ [ "@babel/preset-env", { "targets": { "node": "current" } } ] ], "plugins": ["angularjs-annotate"] } .editorconfig000066400000000000000000000006401520131260200135230ustar00rootroot00000000000000# EditorConfig helps developers define and maintain consistent # coding styles between different editors and IDEs # editorconfig.org root = true [*] # Change these settings to your own preference indent_style = space indent_size = 4 # We recommend you to keep these unchanged end_of_line = lf charset = utf-8 trim_trailing_whitespace = false insert_final_newline = true [*.md] trim_trailing_whitespace = false .github/000077500000000000000000000000001520131260200124065ustar00rootroot00000000000000.github/workflows/000077500000000000000000000000001520131260200144435ustar00rootroot00000000000000.github/workflows/build.yml000066400000000000000000000016761520131260200162770ustar00rootroot00000000000000# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions name: build on: schedule: - cron: '0 0 1 * *' push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest strategy: matrix: node-version: ['lts/*'] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - run: npm i -g grunt-cli - run: npm install - run: grunt .gitignore000066400000000000000000000003441520131260200130370ustar00rootroot00000000000000/build /node_modules /*.log /*.iws .idea/workspace.xml .idea/tasks.xml .idea/profiles_settings.xml .idea/inspectionProfiles/Project_Default.xml .idea/inspectionProfiles/profiles_settings.xml node_modules/.yarn-integrity /dist.npmignore000066400000000000000000000002561520131260200130500ustar00rootroot00000000000000/.idea /artifacts /build /test /node_modules /*.iml /*.ipr /*.iws /.travis.yml /.scrutinizer.yml /Gruntfile.js /*.lock *.log /corifeus-boot.json /secure /src/**/*.* /.github .travis.yml000066400000000000000000000014571520131260200131660ustar00rootroot00000000000000language: node_js cache: npm: false node_js: - lts/* before_script: - npm install -g grunt-cli npm env: global: secure: ABatXXM9lXYQ80Ro0nJ15j5BG/XEP5/L3kGEk+HrOOWrfZHvT3Xd1mQFkHBR5UinNy2Kv/IcUu/2eO1t8ZrX0KlZbx32Y/MuinZKsAWDs8Rx3CsqMIU5f9bk6lhvGLcCFL1AN4gn+0Ga1Ta7ggW9MhhscF2cf1j24tZAxK4D48HQZYK3JQ13nhhsM3RIr9nhpipQMBoTyqTFFgRtjGQJHq7kpAV/7yGpP1K5xgarUnzT1hg9n4w3WVlSZRHPLyyBf7+6anWyANBGkqj9w9ggI93aCe/MTP6kHEftMBVrjFrQZgZZW0D5SdxKbY6n4llLK4adnsyXEXQE9Q+iwsaFLYB0hlQgX3BxReaoCc0MwG95lSZ/U7jFZ6KJL/NIoju0zyNiTlnWBz5arvoxEL1yZ+Nq1KKVHykgwVzhrjoyOSHFt7FtMrvm3WCe0NR7sUcDbo2L3ccbWvIMYkvs8A1SrIOUICapet+t+iF5r53VqRwQF6oA7kOM+gZ+sdHOnmsnCwzWWSCkamMZUx2CCzKFERGUP20Yz3UuUGPMYsthSfVpq5Ds0t90voW2RUQa2cgS3nRLaUA+FjWF4wFSkfqS9NxSkK0etiZRYqGNtB/WnQFEKySWsyC9m1rHDn2LlKDrxTgz5d8b7pSXaWU68JMxJEBz4h9HXR/GEdSEqaeIgYQ= Gruntfile.js000066400000000000000000000102151520131260200133420ustar00rootroot00000000000000const utils = require('corifeus-utils'); module.exports = (grunt) => { const builder = require(`corifeus-builder`); const gruntUtil = builder.utils; const loader = new builder.loader(grunt); loader.js({ jit: { injector: 'grunt-injector', }, config: { injector: { options: {}, jsAngular: { options: { transform: function (filePath) { const relative = gruntUtil.injectorRelativePathGenerator({ srcDir: 'src/angular/', filePath: filePath, }) return `require('./${relative}');`; }, starttag: '//injector-angular-start', endtag: '//injector-angular-end' }, files: { 'src/angular/injector.js': [ 'src/angular/**/*.js', '!src/angular/injector.js', '!src/angular/boot.js', '!src/angular/angular-bootstrap.js', '!src/angular/routes.js', ], } }, sass: { options: { transform: function (filePath) { const relative = gruntUtil.injectorRelativePathGenerator({ srcDir: 'src/', filePath: filePath, }) return `@import "./${relative}";`; }, starttag: '//injector-sass-start', endtag: '//injector-sass-end', }, files: { 'src/injector.scss': [ 'src/**/*.scss', '!src/scss/index.scss', '!src/injector.scss', '!src/vendor.scss', ] } }, }, watch: { options: { atBegin: true }, js: { files: [ 'src/angular/**/*.js', '!src/angular/injector.js', '!src/angular/boot.js', '!src/angular/routes.js', ], tasks: [ 'injector:jsAngular', ], }, sass: { files: [ 'src/**/*.scss', '!src/scss/index.scss', '!src/injector.scss', ], tasks: [ 'injector:sass' ], }, }, } }); grunt.registerTask('default', ['cory-npm', 'clean', 'cory-replace', 'cory:license', 'injector', 'publish']); grunt.registerTask('inject', ['watch:js', 'watch:sass']); grunt.registerTask('build', ['injector']); grunt.registerTask('publish', async function() { const done = this.async() const cwd = process.cwd() try { await gruntUtil.spawn({ grunt: grunt, gruntThis: this, }, { cmd: `${cwd}/node_modules/.bin/grunt${gruntUtil.commandAddon}`, args: [ 'injector' ] }); await gruntUtil.spawn({ grunt: grunt, gruntThis: this, }, { cmd: `${cwd}/node_modules/.bin/webpack${gruntUtil.commandAddon}`, args: [ '--config', './src/builder/webpack.config.js', '--mode=production' ] }); done() } catch(e) { done(e) } }) } LICENSE000066400000000000000000000024321520131260200120540ustar00rootroot00000000000000 @license p3x-redis-ui-material v2022.4.102 💿 The p3x-redis-ui-material web interface that connects to the p3x-redis-ui-server via http and socket.io https://corifeus.com/redis-ui-material Copyright (c) 2022 Patrik Laszlo / P3X / Corifeus and contributors. MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. README.md000066400000000000000000000066461520131260200123410ustar00rootroot00000000000000# This is a development package For the full-blown package, please follow: https://github.com/patrikx3/redis-ui https://www.npmjs.com/package/p3x-redis-ui https://corifeus.com/redis-ui [//]: #@corifeus-header [![Donate for Corifeus / P3X](https://img.shields.io/badge/Donate-Corifeus-003087.svg)](https://paypal.me/patrikx3) [![Contact Corifeus / P3X](https://img.shields.io/badge/Contact-P3X-ff9900.svg)](https://www.patrikx3.com/en/front/contact) [![Corifeus @ Facebook](https://img.shields.io/badge/Facebook-Corifeus-3b5998.svg)](https://www.facebook.com/corifeus.software) [![Build Status](https://github.com/patrikx3/redis-ui-material/workflows/build/badge.svg)](https://github.com/patrikx3/redis-ui-material/actions?query=workflow%3Abuild) [![Uptime Robot ratio (30 days)](https://img.shields.io/uptimerobot/ratio/m780749701-41bcade28c1ea8154eda7cca.svg)](https://stats.uptimerobot.com/9ggnzcWrw) --- # 💿 The p3x-redis-ui-material web interface that connects to the p3x-redis-ui-server via http and socket.io v2022.4.103 **Bugs are evident™ - MATRIX️** ### NodeJS LTS is supported ### Built on NodeJs version ```txt v16.13.1 ``` # Description [//]: #@corifeus-header:end The is the `p3x-redis-ui-material` web gui, that uses the `p3x-redis-ui-server`. It is based on Socket.IO and AngularJs Material, uses themes light/dark schema and internationalization (English is implemented by default). # For development standalone For file names do not use camelCase, but use kebab-case. Folder should be named as kebab-case as well. As you can see, all code filenames are using it like that, please do not change that. Please apply the `.editorconfig` settings in your IDE. Make sure that the server app is running at for development standalone: https://github.com/patrikx3/redis-ui-server Then: ```bash npm install npm run dev ``` The frontend is available @ http://localhost:8080 [//]: #@corifeus-footer --- 🙏 This is an open-source project. Star this repository, if you like it, or even donate to maintain the servers and the development. Thank you so much! Possible, this server, rarely, is down, please, hang on for 15-30 minutes and the server will be back up. All my domains ([patrikx3.com](https://patrikx3.com) and [corifeus.com](https://corifeus.com)) could have minor errors, since I am developing in my free time. However, it is usually stable. **Note about versioning:** Versions are cut in Major.Minor.Patch schema. Major is always the current year. Minor is either 4 (January - June) or 10 (July - December). Patch is incremental by every build. If there is a breaking change, it should be noted in the readme. --- [**P3X-REDIS-UI-MATERIAL**](https://corifeus.com/redis-ui-material) Build v2022.4.103 [![Donate for Corifeus / P3X](https://img.shields.io/badge/Donate-Corifeus-003087.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QZVM4V6HVZJW6) [![Contact Corifeus / P3X](https://img.shields.io/badge/Contact-P3X-ff9900.svg)](https://www.patrikx3.com/en/front/contact) [![Like Corifeus @ Facebook](https://img.shields.io/badge/LIKE-Corifeus-3b5998.svg)](https://www.facebook.com/corifeus.software) ## P3X Sponsor [IntelliJ - The most intelligent Java IDE](https://www.jetbrains.com/?from=patrikx3) [![JetBrains](https://cdn.corifeus.com/assets/svg/jetbrains-logo.svg)](https://www.jetbrains.com/?from=patrikx3) [//]: #@corifeus-footer:end artifacts/000077500000000000000000000000001520131260200130265ustar00rootroot00000000000000artifacts/reduce-bundle-size.txt000066400000000000000000000022451520131260200172600ustar00rootroot000000000000002020 October 18 08:00 AM -r--r----- 1 www-data www-data 2.3K Oct 17 20:38 2eb6240af39282952504b5e016895183.js -r--r----- 1 www-data www-data 2.6K Oct 17 20:38 59bde89bce5c1126ba5ee99c55ec48c8.js -r--r----- 1 www-data www-data 186K Oct 17 20:38 main.3b4993afb7ef0c773dd2.js -r--r----- 1 www-data www-data 12K Oct 17 20:38 main.82603f4092c1cd8f8cf9.css -r--r----- 1 www-data www-data 2.2M Oct 17 20:38 vendor.2bf99f4796897bbcdde3.js -r--r----- 1 www-data www-data 500K Oct 17 20:38 vendor.8cec4ee3d875369b3db2.css 2955,7 2020 October 18 11:00 AM -r-------- 1 www-data www-data 2.3K Oct 18 10:43 2eb6240af39282952504b5e016895183.js -r-------- 1 www-data www-data 2.6K Oct 18 10:43 59bde89bce5c1126ba5ee99c55ec48c8.js -r-------- 1 www-data www-data 23K Oct 18 10:43 f7186078e00d958aa2b316483dfc7e1c.js -r-------- 1 www-data www-data 1.2M Oct 18 10:43 362.chunk.js -r-------- 1 www-data www-data 189K Oct 18 10:43 main.5bb26a2fed2bb6572b27.js -r-------- 1 www-data www-data 12K Oct 18 10:43 main.f0afde82d9f3f4ba2c8d.css -r-------- 1 www-data www-data 925K Oct 18 10:43 vendor.423e956f43a2d1406ae5.js -r-------- 1 www-data www-data 500K Oct 18 10:43 vendor.8adbf377a94fd3e73b2c.css 2882,7 package.json000066400000000000000000000070001520131260200133310ustar00rootroot00000000000000{ "name": "p3x-redis-ui-material", "version": "2022.4.103", "description": "💿 The p3x-redis-ui-material web interface that connects to the p3x-redis-ui-server via http and socket.io", "corifeus": { "icon": "fas fa-database", "code": "Fireball", "opencollective": false, "build": true, "nodejs": "v16.13.1", "reponame": "redis-ui-material", "publish": true, "prefix": "p3x-", "type": "p3x" }, "main": "src/index.js", "scripts": { "test": "grunt", "dev": "concurrently \"grunt watch:js\" \"grunt watch:sass\" \"webpack serve --hot --config ./src/builder/webpack.config.js\"", "dev-webpack": "webpack serve --config ./src/builder/webpack.config.js", "build": "grunt build && webpack --config ./src/builder/webpack.config.js --mode=production", "stats": "grunt build && WEBPACK_STATS=1 webpack --mode=production --config ./src/builder/webpack.config.js && webpack-bundle-analyzer ./dist/stats.json" }, "repository": { "type": "git", "url": "https://github.com/patrikx3/redis-ui-material.git" }, "keywords": [ "redis", "ui", "gui", "web", "electron", "desktop", "server", "angularjs", "javascript", "material", "dark", "light" ], "author": "Patrik Laszlo ", "license": "MIT", "devDependencies": { "@babel/core": "^7.16.7", "@babel/preset-env": "^7.16.7", "@fontsource/roboto": "^4.5.1", "@fontsource/roboto-mono": "^4.5.0", "@fortawesome/fontawesome-free": "^5.15.4", "@uirouter/angularjs": "^1.0.30", "angular": "^1.8.2", "angular-animate": "^1.8.2", "angular-aria": "^1.8.2", "angular-cookies": "^1.8.2", "angular-inview": "^3.1.0", "angular-json-tree": "^1.1.0", "angular-material": "=1.2.4", "angular-messages": "^1.8.2", "angular-sanitize": "^1.8.2", "angular-tree-control": "git+https://github.com/wix/angular-tree-control.git", "babel-loader": "^8.2.3", "babel-plugin-angularjs-annotate": "^0.10.0", "clean-webpack-plugin": "^4.0.0", "concurrently": "^7.0.0", "copy-webpack-plugin": "^10.2.0", "corifeus-builder": "^2022.4.101", "css-loader": "^6.5.1", "css-minimizer-webpack-plugin": "^3.3.1", "grunt-injector": "^1.1.0", "html-loader": "^3.0.1", "html-webpack-plugin": "^5.5.0", "humanize-duration": "^3.27.1", "jquery": "^3.6.0", "js-htmlencode": "^0.3.0", "jsoneditor": "^9.5.11", "lodash": "^4.17.21", "material-design-icons-iconfont": "^6.1.1", "mini-css-extract-plugin": "^2.4.5", "mobile-detect": "^1.4.5", "node-sass": "^7.0.1", "pretty-bytes": "^5.6.0", "raw-loader": "^4.0.2", "sass-loader": "^12.4.0", "socket.io-client": "^4.4.0", "source-map-loader": "^3.0.1", "style-loader": "^3.3.1", "terser-webpack-plugin": "^5.3.0", "timestring": "^6.0.0", "webpack": "^5.65.0", "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^4.9.1", "webpack-dev-server": "^4.7.2", "webpack-remove-debug": "^0.1.0" }, "engines": { "node": ">=12.13.0" }, "homepage": "https://corifeus.com/redis-ui-material", "dependencies": { "moment": "^2.29.1" } }redis-ui-material.iml000066400000000000000000000005171520131260200150710ustar00rootroot00000000000000 src/000077500000000000000000000000001520131260200116355ustar00rootroot00000000000000src/angular/000077500000000000000000000000001520131260200132665ustar00rootroot00000000000000src/angular/angular-bootstrap.js000066400000000000000000000007071520131260200172740ustar00rootroot00000000000000module.exports = () => { angular.element(document).ready(() => { try { const bootstrapElement = document.getElementById('p3xr-redis-ui-bootstrap'); angular.bootstrap(bootstrapElement, ['p3xr-redis-ui']); } catch(e) { if (e && e.message && e.message.includes('bootstrapped')) { location.reload() } else { console.error(e) } } }) } src/angular/boot.js000066400000000000000000000343451520131260200146000ustar00rootroot00000000000000 p3xr.ng = angular.module('p3xr-redis-ui', [ 'ngCookies', 'ngAnimate', 'ngAria', 'ngSanitize', 'ngMessages', 'ngMaterial', 'ui.router', 'treeControl', 'angular-json-tree', 'angular-inview', ]); require('./injector') p3xr.ng.config(($qProvider, $locationProvider, $urlRouterProvider, $stateProvider, p3xrThemeProvider, $mdAriaProvider) => { $mdAriaProvider.disableWarnings(); $qProvider.errorOnUnhandledRejections(false); $locationProvider.html5Mode(true); // $urlRouterProvider.otherwise('/'); // $httpProvider.interceptors.push('ngivrHttpInterceptor'); p3xrThemeProvider.start(); const routes = require('./routes') $urlRouterProvider.otherwise('/main'); routes($stateProvider); }) p3xr.ng.run(($rootScope, p3xrSocket, p3xrTheme, $mdMedia, $state, $timeout, $cookies, p3xrRedisParser, $animate) => { $rootScope.p3xr = p3xr; $rootScope.$mdMedia = $mdMedia; $rootScope.isElectron = (/electron/i.test(navigator.userAgent)) $rootScope.hasConnected = () => { if (Object.keys(p3xr.state.redisConnections).length === 0) { return false } return true; } $rootScope.locationReload = () => { // $state.go('main') // location.reload() location.href = '/' } let search Object.defineProperty($rootScope.p3xr.state, 'search', { get: () => { search = $cookies.get('p3xr-state-search') //console.warn('search', search) if (search === undefined) { search = '' } return search }, set: (value) => { //console.warn(`set value ${value}`) search = value search = $cookies.put('p3xr-state-search', value, { expires: p3xr.settings.cookieExpiry, }) } }) let treeDivider Object.defineProperty($rootScope.p3xr.settings, 'redisTreeDivider', { get: () => { treeDivider = $cookies.get(p3xr.settings.tree.cookieName) if (treeDivider === undefined) { treeDivider = p3xr.settings.tree.defaultDivider } return treeDivider }, set: (value) => { treeDivider = value treeDivider = $cookies.put(p3xr.settings.tree.cookieName, value, { expires: p3xr.settings.cookieExpiry, }) } }) let jsonFormat Object.defineProperty($rootScope.p3xr.settings, 'jsonFormat', { get: () => { jsonFormat = $cookies.get(p3xr.settings.jsonFormatSettings.cookieName) if (jsonFormat === undefined) { jsonFormat = p3xr.settings.jsonFormatSettings.default } return parseInt(jsonFormat) }, set: (value) => { jsonFormat = value jsonFormat = $cookies.put(p3xr.settings.jsonFormatSettings.cookieName, value, { expires: p3xr.settings.cookieExpiry, }) } }) const setAnimation = () => { console.log('set animation', $rootScope.p3xr.settings.animation) $animate.enabled($rootScope.p3xr.settings.animation) if ($rootScope.p3xr.settings.animation) { $body.removeClass('p3xr-no-animation') } else { $body.addClass('p3xr-no-animation') } } let animation Object.defineProperty($rootScope.p3xr.settings, 'animation', { get: () => { animation = $cookies.get(p3xr.settings.animationSettings.cookieName) if (animation === undefined) { animation = p3xr.settings.animationSettings.default } return parseInt(animation) === 1 }, set: (value) => { animation = value animation = $cookies.put(p3xr.settings.animationSettings.cookieName, value, { expires: p3xr.settings.cookieExpiry, }) setAnimation() } }) setAnimation() let maxValueDisplay Object.defineProperty($rootScope.p3xr.settings, 'maxValueDisplay', { get: () => { maxValueDisplay = $cookies.get(p3xr.settings.maxValueDisplaySetting.cookieName) if (maxValueDisplay === undefined) { maxValueDisplay = p3xr.settings.maxValueDisplaySetting.default } return parseInt(maxValueDisplay) }, set: (value) => { maxValueDisplay = parseInt(value) maxValueDisplay = $cookies.put(p3xr.settings.maxValueDisplaySetting.cookieName, value, { expires: p3xr.settings.cookieExpiry, }) } }) let maxKeysDisplay Object.defineProperty($rootScope.p3xr.settings, 'maxKeys', { get: () => { maxKeysDisplay = $cookies.get(p3xr.settings.maxKeysSettings.cookieName) if (maxKeysDisplay === undefined) { maxKeysDisplay = p3xr.settings.maxKeysSettings.default } let value = parseInt(maxKeysDisplay) if (isNaN(value) || value < 5 || value > p3xr.settings.maxKeysSettings.max) { value = p3xr.settings.maxKeysSettings.default } return value }, set: (value) => { maxKeysDisplay = parseInt(value) maxKeysDisplay = $cookies.put(p3xr.settings.maxKeysSettings.cookieName, value, { expires: p3xr.settings.cookieExpiry, }) } }) let language Object.defineProperty($rootScope.p3xr.settings.language, 'current', { get: () => { language = $cookies.get(p3xr.settings.language.cookieName) if (language === undefined) { language = p3xr.settings.language.defaultLanguage require('moment').locale(p3xr.settings.language.momentDateMap[language]) } return language }, set: (value) => { //console.warn('p3xr-language set incoming' , value) if (value === undefined) { value = p3xr.settings.language.defaultLanguage } //console.warn('p3xr-language set actual' , value) language = value require('moment').locale(p3xr.settings.language.momentDateMap[language]) $rootScope.p3xr.strings = p3xr.settings.language.translation[value] //console.warn('p3xr-language set strings' , $rootScope.p3xr.strings) language = $cookies.put(p3xr.settings.language.cookieName, value, { expires: p3xr.settings.cookieExpiry, }) } }) $rootScope.p3xr.settings.language.current = $cookies.get(p3xr.settings.language.cookieName) let keysSort Object.defineProperty($rootScope.p3xr.settings, 'keysSort', { get: () => { keysSort = $cookies.get(p3xr.settings.keySortInfo.cookieName) if (keysSort === undefined) { keysSort = p3xr.settings.keySortInfo.default } else if (keysSort === 'true') { keysSort = true } else if (keysSort === 'false') { keysSort = false } return keysSort }, set: (value) => { keysSort = value keysSort = $cookies.put(p3xr.settings.keySortInfo.cookieName, value, { expires: p3xr.settings.cookieExpiry, }) } }) let searchClientSide Object.defineProperty($rootScope.p3xr.settings, 'searchClientSide', { get: () => { searchClientSide = $cookies.get(p3xr.settings.searchInfoClientSide.cookieName) if (searchClientSide === undefined) { searchClientSide = p3xr.settings.searchInfoClientSide.default } else if (searchClientSide === 'true') { searchClientSide = true } else if (searchClientSide === 'false') { searchClientSide = false } if (p3xr.state.keysRaw.length > p3xr.settings.maxLightKeysCount || p3xr.state.dbsize > p3xr.settings.maxLightKeysCount) { searchClientSide = false } return searchClientSide }, set: (value) => { searchClientSide = value searchClientSide = $cookies.put(p3xr.settings.searchInfoClientSide.cookieName, value, { expires: p3xr.settings.cookieExpiry, }) } }) let searchStartsWith Object.defineProperty($rootScope.p3xr.settings, 'searchStartsWith', { get: () => { searchStartsWith = $cookies.get(p3xr.settings.searchInfoStartsWith.cookieName) if (searchStartsWith === undefined) { searchStartsWith = p3xr.settings.searchInfoStartsWith.default } else if (searchStartsWith === 'true') { searchStartsWith = true } else if (searchStartsWith === 'false') { searchStartsWith = false } return searchStartsWith }, set: (value) => { searchStartsWith = value searchStartsWith = $cookies.put(p3xr.settings.searchInfoStartsWith.cookieName, value, { expires: p3xr.settings.cookieExpiry, }) } }) let expandedNodes = [] Object.defineProperty($rootScope, 'expandedNodes', { get: () => { //console.warn('expandedNodes get', expandedNodes) return expandedNodes }, set: (value) => { //console.warn('expandedNodes set', expandedNodes) expandedNodes = value } }) $rootScope.savedExpandedNodes = [] let page = 1 Object.defineProperty($rootScope.p3xr.state, 'page', { get: () => { return page }, set: (value) => { page = parseInt(value) } }) $rootScope.keysTreeRendered = [] let keysTree Object.defineProperty($rootScope, 'keysTree', { get: () => { //const startNow = Date.now() if ($rootScope.p3xr.state.redisChanged === true || JSON.stringify(keysTree) !== JSON.stringify(p3xr.state.keys)) { $rootScope.p3xr.state.redisChanged = false $rootScope.keysTreeRendered = p3xrRedisParser.keysToTreeControl({ keys: p3xr.state.keys, }) keysTree = p3xr.state.keys } //console.log('keysTreeRendered', $rootScope.keysTreeRendered) return $rootScope.keysTreeRendered }, }) /* let chunked = [] let chunks = [] Object.defineProperty($rootScope, 'keysTreeChunked', { get: () => { if ($rootScope.keysTree.length < 50) { return $rootScope.keysTree; } let i, j, chunk = 50; for (i = 0, j = $rootScope.keysTree.length; i < j; i += chunk) { chunks.push($rootScope.keysTree.slice(i, i + chunk)); } console.log(chunks) return chunks } }) */ let globalKeysRaw = []; Object.defineProperty($rootScope.p3xr.state, 'keys', { get: () => { //const startNow = Date.now() globalKeysRaw = $rootScope.p3xr.state.keysRaw.slice() if ($rootScope.p3xr.settings.searchClientSide && typeof ($rootScope.p3xr.state.search) === 'string' && $rootScope.p3xr.state.search.length > 0) { //console.log($rootScope.p3xr.settings.searchStartsWith) if ($rootScope.p3xr.settings.searchStartsWith) { //console.log('startswith') globalKeysRaw = globalKeysRaw.filter(keyRaw => { return keyRaw.startsWith($rootScope.p3xr.state.search) }) } else { //console.log('includes') globalKeysRaw = globalKeysRaw.filter(keyRaw => { return keyRaw.includes($rootScope.p3xr.state.search) }) } } if (globalKeysRaw <= $rootScope.p3xr.settings.pageCount) { return globalKeysRaw } else { //console.log('new scope change', ($rootScope.p3xr.state.page -1) * $rootScope.p3xr.settings.pageCount, $rootScope.p3xr.settings.pageCount) const start = ($rootScope.p3xr.state.page - 1) * $rootScope.p3xr.settings.pageCount const keys = globalKeysRaw.slice(start, start + $rootScope.p3xr.settings.pageCount) //console.warn('parse keys', ((Date.now() - startNow)) / 1000) return keys } } }) Object.defineProperty($rootScope.p3xr.state, 'pages', { get: () => { return Math.ceil(globalKeysRaw.length / $rootScope.p3xr.settings.pageCount) //const pages = Math.ceil($rootScope.p3xr.state.keysRaw.length / $rootScope.p3xr.settings.pageCount) //return pages } }) let pageCount Object.defineProperty($rootScope.p3xr.settings, 'pageCount', { get: () => { pageCount = $cookies.get(p3xr.settings.paging.cookieName) if (pageCount === undefined) { pageCount = p3xr.settings.paging.default } else { pageCount = parseInt(pageCount) } return pageCount }, set: (value) => { pageCount = value pageCount = $cookies.put(p3xr.settings.paging.cookieName, value, { expires: p3xr.settings.cookieExpiry, }) } }) let keyPageCount Object.defineProperty($rootScope.p3xr.settings, 'keyPageCount', { get: () => { keyPageCount = $cookies.get(p3xr.settings.keyPage.cookieName) if (keyPageCount === undefined) { keyPageCount = p3xr.settings.keyPage.default } else { keyPageCount = parseInt(keyPageCount) } return keyPageCount }, set: (value) => { keyPageCount = value keyPageCount = $cookies.put(p3xr.settings.keyPage.cookieName, value, { expires: p3xr.settings.cookieExpiry, }) } }) //console.warn('p3xrTheme', p3xrTheme) p3xrTheme.start() console.info('P3X Redis UI ran') }) require('./angular-bootstrap')() src/angular/dialog/000077500000000000000000000000001520131260200145255ustar00rootroot00000000000000src/angular/dialog/p3xr-dialog-connection.html000066400000000000000000000303361520131260200217060ustar00rootroot00000000000000

{{ $root.p3xr.state.cfg.readonlyConnections ? $root.p3xr.strings.label.connectiondView : options.type === 'new' ? $root.p3xr.strings.label.connectiondAdd : $root.p3xr.strings.label.connectiondEdit }}

close
{{ $root.p3xr.strings.form.error.required }}
{{ $root.p3xr.strings.form.error.port }}
{{ $root.p3xr.strings.label.passwordSecure }}

{{ $root.p3xr.strings.label.tlsWithoutCert }} {{ $root.p3xr.strings.label.tlsRejectUnauthorized }}
{{ $root.p3xr.strings.label.tlsSecure }}

{{ $root.p3xr.strings.label.tlsSecure }}

{{ $root.p3xr.strings.label.tlsSecure }}

{{ model.readonly ? $root.p3xr.strings.label.readonly.on : $root.p3xr.strings.label.readonly.off }}
{{ model.cluster ? $root.p3xr.strings.label.cluster.on : $root.p3xr.strings.label.cluster.off }} add {{ $root.p3xr.strings.label.addNode }}
Node {{$index + 1}}
{{ $root.p3xr.strings.confirm.deleteConnectionText }} delete {{ $root.p3xr.strings.label.addNode }} add
{{ $root.p3xr.strings.form.error.port }}
{{ $root.p3xr.strings.form.error.required }}
{{ $root.p3xr.strings.label.passwordSecure }}
 
cancel {{ $root.p3xr.strings.intention.cancel }} {{ $root.p3xr.strings.intention.cancel }} {{ $root.p3xr.strings.intention.testConnection }} {{ options.type === 'new' ? 'add' : 'save' }} {{ options.type === 'new' ? $root.p3xr.strings.intention.add : $root.p3xr.strings.intention.save }}
src/angular/dialog/p3xr-dialog-connection.js000066400000000000000000000211341520131260200213520ustar00rootroot00000000000000p3xr.ng.factory('p3xrDialogConnection', function (p3xrCommon, $mdDialog, p3xrSocket) { return new function () { this.show = async (options) => { try { const result = await $mdDialog.show({ controller: function ($scope, $mdDialog) { $scope.options = options if (options.model !== undefined) { $scope.model = options.model $scope.model.password = options.model.id $scope.model.tlsCrt = options.model.id $scope.model.tlsKey = options.model.id $scope.model.tlsCa = options.model.id } else { $scope.model = { name: undefined, host: undefined, port: undefined, password: undefined, username: undefined, id: undefined, readonly: undefined, tlsWithoutCert: false, tlsRejectUnauthorized: true, tlsCrt: undefined, tlsKey: undefined, tlsCa: undefined, } } if (!$scope.model.hasOwnProperty('cluster')) { $scope.model.cluster = false } if (!$scope.model.hasOwnProperty('nodes')) { $scope.model.nodes = [] } for (let node of $scope.model.nodes) { node.password = node.id } // Promise reject $scope.cancel = function () { /* p3xrCommon.toast({ message: p3xr.strings.status.cancelled }) */ $mdDialog.cancel(); }; /* // Promise resolve $scope.hide = function () { $mdDialog.hide(); }; // Promise resolve - with result $scope.answer = function (answer) { $mdDialog.hide(answer); }; */ //console.warn('$scope.model', $scope.model) const handleInvalidForm = () => { if ($scope.p3xrConnectionForm.$invalid) { p3xrCommon.toast({ message: p3xr.strings.form.error.invalid }) return false } return true } $scope.addNode = (index) => { const newNode = { host: undefined, port: undefined, password: undefined, username: undefined, id: p3xr.nextId(), } if (index === undefined) { $scope.model.nodes.push(newNode) } else { $scope.model.nodes.splice(index + 1, 0, newNode) } } $scope.removeNode = async (ev, index) => { try { await p3xrCommon.confirm({ event: ev, message: p3xr.strings.confirm.deleteConnectionText }); $scope.model.nodes.splice(index, 1) p3xrCommon.toast({ message: p3xr.strings.status.nodeRemoved }) } catch (e) { if (e === undefined) { /* p3xrCommon.toast({ message: p3xr.strings.status.cancelled }); */ return; } p3xrCommon.generalHandleError(e) } } $scope.testConnection = async () => { $scope.p3xrConnectionForm.$setSubmitted(); if (!handleInvalidForm()) { return; } try { p3xr.ui.overlay.show({ message: p3xr.strings.title.connectingRedis }) //await new Promise(resolve => setTimeout(resolve, 5000)) const response = await p3xrSocket.request({ action: 'redis-test-connection', payload: { model: $scope.model }, }) p3xrCommon.toast({ message: p3xr.strings.status.redisConnected }) } catch (e) { p3xrCommon.generalHandleError(e) } finally { p3xr.ui.overlay.hide() } } $scope.submit = async () => { if (!handleInvalidForm()) { return; } if ($scope.model.host === undefined) { $scope.model.host = 'localhost' } if ($scope.model.port === undefined) { $scope.model.port = 6379 } if (options.type === 'new') { $scope.model.id = p3xr.nextId() } for (let node of $scope.model.nodes) { if (node.host === undefined) { node.host = 'localhost' } if (node.id === undefined) { node.id = p3xr.nextId() } } try { const response = await p3xrSocket.request({ action: 'connection-save', payload: { model: angular.copy($scope.model) }, }) p3xrCommon.toast({ message: $scope.options.type === 'new' ? p3xr.strings.status.added : p3xr.strings.status.saved }) //$scope.options.type = 'edit'; $mdDialog.cancel(); } catch (e) { p3xrCommon.generalHandleError(e) } } }, template: require('./p3xr-dialog-connection.html'), parent: angular.element(document.body), targetEvent: options.$event, clickOutsideToClose: true, fullscreen: true // Only for -xs, -sm breakpoints. }) // console.warn(result) } catch (error) { p3xrCommon.generalHandleError(error) } } } }); src/angular/dialog/p3xr-dialog-connection.scss000066400000000000000000000000001520131260200216760ustar00rootroot00000000000000src/angular/dialog/p3xr-dialog-json-editor.html000066400000000000000000000051651520131260200220060ustar00rootroot00000000000000
edit   {{ $root.p3xr.strings.intention.jsonViewEditor }} close
{{ $root.p3xr.strings.label.jsonViewNotParsable}}
{{ $root.p3xr.strings.label.jsonViewNotParsable}} cancel {{ $root.p3xr.strings.intention.cancel }} {{ $root.p3xr.strings.intention.cancel }} save {{ $root.p3xr.strings.intention.save }} {{ $root.p3xr.strings.intention.save }} save format_line_spacing {{ $root.p3xr.strings.intention.saveWithFormatJson }} {{ $root.p3xr.strings.intention.saveWithFormatJson }}
src/angular/dialog/p3xr-dialog-json-editor.js000066400000000000000000000171661520131260200214620ustar00rootroot00000000000000p3xr.ng.factory('p3xrDialogJsonEditor', function (p3xrCommon, $mdDialog, $timeout) { const debounce = require('lodash/debounce') return new function () { this.show = async(options) => { /* webpackChunkName: "editor" */ await import( /* webpackPrefetch: true */ "../../editor" ) return $mdDialog.show({ controller: function ($scope, $mdDialog, p3xrCommon, $rootScope, p3xrTheme, $mdMedia) { $rootScope.$broadcast('p3xr-main-resizer', { drag: false }) let editor let obj try { obj = JSON.parse(options.value) $scope.isJson = true } catch (e) { obj = undefined $scope.isJson = false } if ($scope.isJson) { // https://webpack.js.org/guides/code-splitting/ // /* webpackMode: "lazy" */ const execAsync = async() => { try { $timeout(() => { // en , zn let language switch(p3xr.settings.language.current) { case 'zn': language = 'zh-CN' break; default: language = 'en' break; } const container = document.getElementById("p3xr-jsoneditor") const options = { //sortObjectKeys: false, limitDragging: false, modes: ['tree', 'code', 'view', 'preview'], //history: false, mode: 'code', //search: true, //mainMenuBar: false, language: language, //enableSort: false, //enableTransform: false, //ace: ace, indentation: p3xr.settings.jsonFormat, //theme: p3xrTheme.isDark() ? 'ace/theme/twilight' : 'ace/theme/github' } if (p3xrTheme.isDark()) { options.theme = 'ace/theme/twilight' } /* if (JSON.stringify(obj).length > 10240) { p3xrCommon.toast({ message: p3xr.strings.label.bigJson, hideDelay: 10000 }) } */ editor = new JSONEditor(container, options, obj) }) } catch(e) { p3xrCommon.generalHandleError(e) } } execAsync() } const close = (event) => { const keycode = event.which || event.keyCode; // If this is the escape key //console.log('close') if ( keycode === 27 ) { event.preventDefault(); event.stopPropagation(); // $mdDialog.cancel(); const pico = $('.pico-close') if (pico.length > 0) { pico.click() } else { $mdDialog.cancel(); } } } document.documentElement.addEventListener('keydown', close, true) const resize = () => { if ($mdMedia('(max-width:959px)')) { $scope.minHeight = '100%' } else { $scope.minHeight = `${Math.max(10, window.innerHeight - 100)}px` } } resize() const editorResize = debounce(() => { if (editor && editor.aceEditor) { console.log('resize json editor ace resize') resize() $scope.$digest() editor.aceEditor.resize() } }, p3xr.settings.debounce) $window.on('resize', editorResize) $scope.$on('$destroy', () => { $window.off('resize', editorResize) if (editor){ editor.destroy() editor = undefined } $rootScope.$broadcast('p3xr-main-resizer', { drag: true }) document.documentElement.removeEventListener('keydown', close, true) }) // Promise reject $scope.ok = function () { $mdDialog.cancel(); }; // Promise resolve $scope.save = function ({ format }) { try { $mdDialog.hide({ obj: JSON.stringify(editor.get(), null, format ? p3xr.settings.jsonFormat : 0) }); } catch(e) { p3xrCommon.generalHandleError(e) } }; /* // Promise resolve - with result $scope.answer = function (answer) { $mdDialog.hide(answer); }; */ }, template: require('./p3xr-dialog-json-editor.html'), parent: angular.element(document.body), targetEvent: options.$event, clickOutsideToClose: false, fullscreen: true, // Only for -xs, -sm breakpoints. multiple: true, escapeToClose: false, }) } } }); src/angular/dialog/p3xr-dialog-json-editor.scss000066400000000000000000000003061520131260200220050ustar00rootroot00000000000000.jsoneditor-poweredBy { display: none; } .ace_mobile-menu { display: none !important } @media (min-width:960px) { md-dialog.fullscreen-dialog-fix-width { min-width: 75%; } } src/angular/dialog/p3xr-dialog-json-view.html000066400000000000000000000041761520131260200214730ustar00rootroot00000000000000
table_chart   {{ $root.p3xr.strings.intention.jsonViewShow }} {{ $root.p3xr.strings.page.treeControls.expandAll}} keyboard_arrow_down {{ $root.p3xr.strings.page.treeControls.collapseAll}} keyboard_arrow_up close
{{ $root.p3xr.strings.label.jsonViewNotParsable}}
close {{ $root.p3xr.strings.intention.close }}
src/angular/dialog/p3xr-dialog-json-view.js000066400000000000000000000046141520131260200211400ustar00rootroot00000000000000p3xr.ng.factory('p3xrDialogJsonView', function (p3xrCommon, $mdDialog) { return new function () { this.show = async (options) => { try { const result = await $mdDialog.show({ controller: function ($scope, $mdDialog, $timeout) { $scope.treeExpandAll = () => { p3xr.ui.overlay.show({ message: p3xr.strings.title.jsonRecursive }) $timeout(() => { $scope.howExpanded = 'recursive' $timeout(() => { p3xr.ui.overlay.hide() }) }) } $scope.treeCollapseAll = () => { $scope.howExpanded = true } try { $scope.howExpanded = true $scope.obj = JSON.parse(options.value) $scope.isJson = true } catch (e) { $scope.obj = undefined $scope.isJson = false } // Promise reject $scope.ok = function () { $mdDialog.cancel(); }; /* // Promise resolve $scope.hide = function () { $mdDialog.hide(); }; // Promise resolve - with result $scope.answer = function (answer) { $mdDialog.hide(answer); }; */ }, template: require('./p3xr-dialog-json-view.html'), parent: angular.element(document.body), targetEvent: options.$event, clickOutsideToClose: true, fullscreen: true, // Only for -xs, -sm breakpoints. multiple: true, }) // console.warn(result) } catch (error) { p3xrCommon.generalHandleError(error) } } } }); src/angular/dialog/p3xr-dialog-json-view.scss000066400000000000000000000005751520131260200215010ustar00rootroot00000000000000json-tree > json-node > ul { margin: 0; } json-tree * { font-size: 13px !important; } json-tree > json-node > span.key { position: relative; top: -8px; } /* json-tree json-node.expandable::before { font-family: 'Font Awesome 5 Free'; content: "\f07b"; } json-tree json-node.expandable.expanded::before { content: "\f07c"; transform: none; } */ src/angular/dialog/p3xr-dialog-key-new-or-set.html000066400000000000000000000216551520131260200223410ustar00rootroot00000000000000

{{ options.type === 'edit' ? $root.p3xr.strings.form.key.label.formName.edit : ( options.type === 'append' ? $root.p3xr.strings.form.key.label.formName.append : $root.p3xr.strings.form.key.label.formName.add ) }}

close
{{ $root.p3xr.strings.form.key.error.key }}
{{ $root.p3xr.strings.redisTypes[type] }}
{{ $root.p3xr.strings.label.redisListIndexInfo }}
{{ $root.p3xr.strings.form.key.error.hashKey }}
{{ $root.p3xr.strings.form.key.error.score }}
{{ $root.p3xr.strings.form.key.error.streamTimestamp }}
{{ $root.p3xr.strings.label.streamTimestampId }}
{{ $root.p3xr.strings.intention.jsonViewEditor }} {{ $root.p3xr.strings.intention.jsonViewEditor }} format_line_spacing {{ $root.p3xr.strings.intention.formatJson }} {{ $root.p3xr.strings.intention.formatJson }} table_chart {{ $root.p3xr.strings.intention.jsonViewShow }} {{ $root.p3xr.strings.intention.jsonViewShow }} {{ $root.p3xr.strings.intention.copy }} content_copy {{ $root.p3xr.strings.label.validateJson }}
{{ $root.p3xr.strings.label.streamValue }}
{{ $root.p3xr.strings.form.key.error.value }}
{{ $root.p3xr.strings.label.jsonViewNotParsable }}
cancel {{ $root.p3xr.strings.intention.cancel }} {{ options.type === 'edit' ? 'edit' : 'add'}} {{ options.type === 'edit' ? $root.p3xr.strings.intention.save : $root.p3xr.strings.intention.add }}
src/angular/dialog/p3xr-dialog-key-new-or-set.js000066400000000000000000000161511520131260200220040ustar00rootroot00000000000000p3xr.ng.factory('p3xrDialogKeyNewOrSet', function (p3xrCommon, $mdDialog, p3xrSocket, p3xrDialogJsonEditor, p3xrDialogJsonView) { return new function () { this.show = (options) => { return new Promise(async (resolve, reject) => { try { const result = await $mdDialog.show({ controller: function ($scope, $mdDialog) { $scope.jsonViewer = (options) => { p3xrDialogJsonView.show({ event: options.$event, value: options.value }) // this.showJson = !this.showJson } $scope.copy = (opts) => { global.p3xr.clipboard({ value: opts.value }) p3xrCommon.toast(p3xr.strings.status.dataCopied) } $scope.types = [ 'string', 'list', 'hash', 'set', 'zset', 'stream', ] $scope.validateJson = false; $scope.model = { type: 'string', key: options.node !== undefined ? options.node.key : '', value: undefined, score: undefined, streamTimestamp: '*', hashKey: undefined, index: undefined, } $scope.options = options; if (options.hasOwnProperty('model')) { Object.assign($scope.model, options.model) } //console.warn($scope.model) // Promise reject $scope.cancel = function () { /* p3xrCommon.toast({ message: p3xr.strings.status.cancelled }) */ $mdDialog.cancel(); reject() }; /* // Promise resolve $scope.hide = function () { $mdDialog.hide(); }; // Promise resolve - with result $scope.answer = function (answer) { $mdDialog.hide(answer); }; */ const handleInvalidForm = () => { if ($scope.p3xrKeyNewForm.$invalid) { p3xrCommon.toast({ message: p3xr.strings.form.error.invalid }) return false } return true } $scope.submit = async () => { if (!handleInvalidForm()) { return; } try { const response = await p3xrSocket.request({ action: 'key-new-or-set', payload: { type: options.type, originalValue: options.hasOwnProperty('model') ? options.model.value : undefined, originalHashKey: options.hasOwnProperty('model') ? options.model.hashKey : undefined, model: angular.copy($scope.model) }, }) window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': '/key-new-or-set' } ); resolve(response) p3xrCommon.toast({ message: p3xr.strings.status.set }) //$scope.options.type = 'edit'; $mdDialog.cancel(); } catch (e) { //reject(e) p3xrCommon.generalHandleError(e) } } $scope.jsonEditor = async(options) => { try { const result = await p3xrDialogJsonEditor.show({ event: options.$event, value: options.value }) $scope.model.value = result.obj $scope.$digest(); } catch(e) { p3xrCommon.generalHandleError(e) } // this.showJson = !this.showJson } $scope.formatJson = () => { try { $scope.model.value = JSON.stringify(JSON.parse($scope.model.value), null, p3xr.settings.jsonFormat) } catch(e) { p3xrCommon.toast({ message: p3xr.strings.label.jsonViewNotParsable }) } } }, template: require('./p3xr-dialog-key-new-or-set.html'), parent: angular.element(document.body), targetEvent: options.$event, clickOutsideToClose: false, fullscreen: true, // Only for -xs, -sm breakpoints. multiple: true, //escapeToClose: false, }) // console.warn(result) } catch (error) { reject(error) p3xrCommon.generalHandleError(error) } }) } } }); src/angular/dialog/p3xr-dialog-treecontrol-settings.html000066400000000000000000000227561520131260200237540ustar00rootroot00000000000000

{{$root.p3xr.strings.form.treeSettings.label.formName}}

close
{{ $root.p3xr.strings.form.treeSettings.keyCount() }}

{{ $root.p3xr.strings.label.tooManyKeys({ count: $root.p3xr.state.keysRaw.length, maxLightKeysCount: $root.p3xr.settings.maxLightKeysCount}) }}

{{ $root.p3xr.strings.label.treeSeparatorEmpty }}

{{ $root.p3xr.strings.form.treeSettings.error.page }}

{{ $root.p3xr.strings.form.treeSettings.error.keyPageCount }}

{{ $root.p3xr.strings.form.treeSettings.error.maxValueDisplay }}
{{ $root.p3xr.strings.form.treeSettings.maxValueDisplayInfo }}

{{ $root.p3xr.strings.form.treeSettings.error.maxKeys }}
{{ $root.p3xr.strings.form.treeSettings.maxKeysInfo }}
{{ model.keysSort ? $root.p3xr.strings.label.keysSort.on : $root.p3xr.strings.label.keysSort.off }}
{{ $root.p3xr.strings.label.treeKeyStore }}
{{ model.searchClientSide ? $root.p3xr.strings.form.treeSettings.label.searchModeClient : $root.p3xr.strings.form.treeSettings.label.searchModeServer }}
{{ $root.p3xr.strings.page.treeControls.search.info }}

{{ $root.p3xr.strings.page.treeControls.search.largeSetInfo }}

{{ model.searchStartsWith ? $root.p3xr.strings.form.treeSettings.label.searchModeStartsWith : $root.p3xr.strings.form.treeSettings.label.searchModeIncludes }} {{ model.jsonFormat ? $root.p3xr.strings.form.treeSettings.label.jsonFormatTwoSpace : $root.p3xr.strings.form.treeSettings.label.jsonFormatFourSpace }} {{ model.animation ? $root.p3xr.strings.form.treeSettings.label.animation : $root.p3xr.strings.form.treeSettings.label.noAnimation }}
cancel {{ $root.p3xr.strings.intention.cancel }} save {{ $root.p3xr.strings.intention.save }}
src/angular/dialog/p3xr-dialog-treecontrol-settings.js000066400000000000000000000122471520131260200234160ustar00rootroot00000000000000p3xr.ng.factory('p3xrDialogTreecontrolSettings', function (p3xrCommon, $mdDialog, $timeout) { return new function () { this.show = async (options) => { try { await $mdDialog.show({ controller: function ($scope, $rootScope) { //console.log('$rootScope.p3xr.settings.maxValueDisplay', $rootScope.p3xr.settings.maxValueDisplay) $scope.model = { treeSeparator: $rootScope.p3xr.settings.redisTreeDivider, pageCount: $rootScope.p3xr.settings.pageCount, keyPageCount: $rootScope.p3xr.settings.keyPageCount, keysSort: $rootScope.p3xr.settings.keysSort, searchClientSide: $rootScope.p3xr.settings.searchClientSide, searchStartsWith: $rootScope.p3xr.settings.searchStartsWith, maxValueDisplay: $rootScope.p3xr.settings.maxValueDisplay, maxKeys: $rootScope.p3xr.settings.maxKeys, jsonFormat: $rootScope.p3xr.settings.jsonFormat === 2, animation: $rootScope.p3xr.settings.animation, } // Promise reject $scope.cancel = function () { /* p3xrCommon.toast({ message: p3xr.strings.status.cancelled }) */ $mdDialog.cancel(); }; /* // Promise resolve $scope.hide = function () { $mdDialog.hide(); }; // Promise resolve - with result $scope.answer = function (answer) { $mdDialog.hide(answer); }; */ const handleInvalidForm = () => { if ($scope.p3xrDialogTreecontrolSettingsForm.$invalid) { p3xrCommon.toast({ message: p3xr.strings.form.error.invalid }) return false } return true } $scope.submit = async () => { if (!handleInvalidForm()) { return; } try { $rootScope.p3xr.settings.redisTreeDivider = $scope.model.treeSeparator $rootScope.p3xr.settings.pageCount = $scope.model.pageCount $rootScope.p3xr.settings.keyPageCount = $scope.model.keyPageCount $rootScope.p3xr.settings.keysSort = $scope.model.keysSort $rootScope.p3xr.settings.searchClientSide = $scope.model.searchClientSide $rootScope.p3xr.settings.searchStartsWith = $scope.model.searchStartsWith $rootScope.p3xr.state.page = 1 $rootScope.p3xr.state.redisChanged = true; $rootScope.p3xr.settings.maxValueDisplay = $scope.model.maxValueDisplay $rootScope.p3xr.settings.maxKeys = $scope.model.maxKeys $rootScope.p3xr.settings.jsonFormat = $scope.model.jsonFormat === true ? 2 : 4 $rootScope.p3xr.settings.animation = $scope.model.animation === true ? 1 : 0 /* $timeout(() => { $rootScope.$digest() }) */ //if ( !$rootScope.p3xr.settings.searchClientSide ) { //if (options.p3xrMainRef !== undefined) { // await options.p3xrMainRef.refresh() //} //} //$scope.options.type = 'edit'; $mdDialog.cancel(); $rootScope.$broadcast('p3x-refresh'); } catch (e) { p3xrCommon.generalHandleError(e) } } }, template: require('./p3xr-dialog-treecontrol-settings.html'), parent: angular.element(document.body), targetEvent: options.$event, clickOutsideToClose: true, fullscreen: true // Only for -xs, -sm breakpoints. }) // console.warn(result) } catch (error) { p3xrCommon.generalHandleError(error) } } } }); src/angular/dialog/p3xr-dialog-ttl.html000066400000000000000000000047411520131260200203530ustar00rootroot00000000000000

{{ $root.p3xr.strings.confirm.ttl.title}}

close
{{ $root.p3xr.strings.confirm.ttl.textContent }}
https://www.npmjs.com/package/timestring
cancel {{ $root.p3xr.strings.intention.cancel }} timer {{ $root.p3xr.strings.intention.ttl }}
src/angular/dialog/p3xr-dialog-ttl.js000066400000000000000000000073151520131260200200230ustar00rootroot00000000000000p3xr.ng.factory('p3xrDialogTtl', function (p3xrCommon, $mdDialog) { const timestring = require('timestring') return new function () { this.show = async (options) => { try { const result = await $mdDialog.show({ controller: function ($scope, $mdDialog) { // Promise reject $scope.cancel = function () { /* p3xrCommon.toast({ message: p3xr.strings.status.cancelled }) */ $mdDialog.cancel(); }; $scope.model = options.model const humanizeDuration = require("humanize-duration"); if (typeof $scope.model.ttl === 'number' && $scope.model.ttl > 0) { $scope.convertTextToTime = humanizeDuration($scope.model.ttl * 1000, { delimiter: ' ', }) } else { $scope.convertTextToTime = ''; } $scope.openTimestringNpm = () => { window.open('https://www.npmjs.com/package/timestring#keywords', '_blank') } let firstWatchConvertTextToTime = true $scope.$watch('convertTextToTime', (newVal, oldValue) => { if (firstWatchConvertTextToTime) { firstWatchConvertTextToTime = !firstWatchConvertTextToTime return } try { $scope.model.ttl = timestring(String(newVal), 's') } catch(e) { console.warn('timestring parse error', e) } }) const handleInvalidForm = () => { if ($scope.p3xrTtlForm.$invalid) { p3xrCommon.toast({ message: p3xr.strings.form.error.invalid }) return false } return true } $scope.submit = async () => { if (!handleInvalidForm()) { return; } try { if (isNaN($scope.model.ttl)) { $scope.model.ttl = Math.round($scope.model.ttl) } const hide = { model: $scope.model, } $mdDialog.hide(hide); } catch (e) { p3xrCommon.generalHandleError(e) } } }, template: require('./p3xr-dialog-ttl.html'), parent: angular.element(document.body), targetEvent: options.$event, clickOutsideToClose: true, // fullscreen: true // Only for -xs, -sm breakpoints. }) // console.warn(result) return result } catch (error) { p3xrCommon.generalHandleError(error) } } } }); src/angular/directive/000077500000000000000000000000001520131260200152445ustar00rootroot00000000000000src/angular/directive/p3x-validate-json.js000066400000000000000000000034631520131260200210600ustar00rootroot00000000000000p3xr.ng.directive('p3xValidateJson', function ($timeout, $rootScope) { return { restrict: 'A', require: 'ngModel', scope: { p3xValidateJsonRequired: '<', model : '=ngModel', }, link: function (scope, elm, attrs, ngModel) { let required = scope.p3xValidateJsonRequired || false let globalValue const setValidate = (isValid) => { ngModel.$setValidity('p3xValidateJson', isValid); } scope.$watch('p3xValidateJsonRequired', (val, oldVal) => { required = val; //console.warn('p3x-validate-json p3xValidateJsonRequired', 'required', required) if (!required) { // ngModel.$modelValue = globalValue setValidate(true) scope.model = globalValue } else { try { JSON.parse(globalValue) setValidate(true) } catch (e) { setValidate(false) } } }) ngModel.$validators.p3xValidateJson = (modelValue, viewValue) => { globalValue = modelValue //console.warn('p3x-validate-json p3xIsJson', 'modelValue', modelValue, 'viewValue', viewValue, 'required', required) if (!required) { setValidate(true) return modelValue } try { JSON.parse(modelValue) setValidate(true) return modelValue } catch (e) { setValidate(false) return false } }; } }; }); src/angular/directive/p3xr-ng-enter.js000066400000000000000000000005651520131260200202210ustar00rootroot00000000000000p3xr.ng.directive('ngEnter', function () { return function (scope, element, attrs) { element.bind("keydown keypress", function (event) { if (event.which === 13) { scope.$apply(function () { scope.$eval(attrs.ngEnter); }); event.preventDefault(); } }); }; })src/angular/factory/000077500000000000000000000000001520131260200147355ustar00rootroot00000000000000src/angular/factory/p3xr-common.js000066400000000000000000000115221520131260200174560ustar00rootroot00000000000000p3xr.ng.factory('p3xrCommon', function ($mdToast, $mdDialog, $mdColors, $rootScope, p3xrRedisParser, $timeout, p3xrTheme) { const generalHandleError = (dataOrError) => { if (dataOrError === undefined) { return; } if (!(dataOrError instanceof Error || dataOrError instanceof Object)) { dataOrError = new Error(dataOrError) } if (dataOrError instanceof Error || dataOrError.status === 'error') { let error if (dataOrError instanceof Error) { error = dataOrError } else { error = dataOrError.error } console.warn('generalHandleError') console.error(error) if (typeof error === 'string' && p3xr.strings.code.hasOwnProperty(error)) { error = new Error(p3xr.strings.code[error]) } else if (error.hasOwnProperty('code') && p3xr.strings.code.hasOwnProperty(error.code)) { error.message = p3xr.strings.code[error.code] } else if (p3xr.strings.code.hasOwnProperty(error.message)) { error.message = p3xr.strings.code[error.message] } result.alert({ title: p3xr.strings.title.error, message: '
' + (error.hasOwnProperty('message') ? error.message : error) + '
', }) return false } return true } const toast = (options) => { if (typeof options === 'string') { options = { message: options } } const template = '' + options.message + '' $mdToast.show({ controller: 'p3xrToastController', template: template, hideDelay: options.hideDelay || p3xr.settings.toast.timeout, position: p3xr.settings.toast.position, }); } const confirm = (options) => { let confirm, title, okButton if (!options.hasOwnProperty('disableCancel')) { confirm = $mdDialog.confirm() title = p3xr.strings.confirm.title okButton = p3xr.strings.intention.sure } else { confirm = $mdDialog.alert() title = p3xr.strings.confirm.info okButton = p3xr.strings.intention.ok } confirm .title(title) .htmlContent(options.message) .targetEvent(options.event) .ok(okButton) .multiple(true) if (!options.hasOwnProperty('disableCancel')) { confirm.cancel(p3xr.strings.intention.cancel); } return $mdDialog.show(confirm) } let lastResponse const loadRedisInfoResponse = (options = {}) => { let response if (!options.response) { response = lastResponse } else { response = options.response } lastResponse = response //console.warn('response', response) console.time('loadRedisInfoResponse') $rootScope.p3xr.state.info = p3xrRedisParser.info(response.info) //$rootScope.p3xr.state.infoObject = response.infoObject $rootScope.p3xr.state.keysRaw = response.keys if ($rootScope.p3xr.settings.keysSort && $rootScope.p3xr.state.keysRaw.length <= p3xr.settings.maxLightKeysCount) { $rootScope.p3xr.state.keysRaw = response.keys.sort(p3xr.sort.naturalCompareDocument()) } else { $rootScope.p3xr.state.keysRaw = response.keys } $rootScope.p3xr.state.keysInfo = response.keysInfo console.timeEnd('loadRedisInfoResponse') /* $timeout(() => { $rootScope.p3xr.state.reducedFunctions = $rootScope.p3xr.state.keysRaw.length > p3xr.settings.maxLightKeysCount $rootScope.$digest() console.timeEnd('loadRedisInfoResponse') }) */ } const result = { inputBackground: () => { return p3xrTheme.isDark() ? 'rgba(64, 64, 64, 1)' : 'white' }, inputBorderColor: () => { return $mdColors.getThemeColor(p3xr.state.themeLayout + '-primary-hue-1') }, inputColor: () => { return p3xrTheme.isDark() ? 'white' : 'black' }, generalHandleError: generalHandleError, toast: toast, alert: (opts) => { if (typeof opts === 'string') { opts = { message: opts } } opts.disableCancel = true return confirm(opts) }, confirm: confirm, loadRedisInfoResponse: loadRedisInfoResponse, } return result; }).controller('p3xrToastController', function ($scope, $mdToast) { $scope.closeToast = function() { $mdToast.hide(); }; }) src/angular/factory/p3xr-key-paging.js000066400000000000000000000035371520131260200202300ustar00rootroot00000000000000p3xr.ng.factory('p3xrKeyPaging', function ($mdToast, $mdDialog, $mdColors, $rootScope, p3xrRedisParser, $timeout,) { return function({ $ctrl, $scope, watch, figurePagingType }) { const figurePaging = () => { switch(figurePagingType) { case 'zset': $ctrl.pages = Math.ceil(Object.keys($ctrl.p3xrValue).length / 2 / p3xr.settings.keyPageCount) break; default: $ctrl.pages = Math.ceil(Object.keys($ctrl.p3xrValue).length / p3xr.settings.keyPageCount) break; } $ctrl.page = 1 } this.figurePaging = figurePaging if (watch !== false) { $scope.$watch('$ctrl.p3xrValue', (n, o) => { figurePaging() }) } $scope.$watch('$root.p3xr.settings.keyPageCount', () => { figurePaging() }) $ctrl.pager = (options) => { const {page} = options ///console.log(page ) switch (page) { case 'prev': if ($ctrl.page - 1 >= 1) { $ctrl.page = $ctrl.page - 1 } break; case 'next': if ($ctrl.page + 1 <= $ctrl.pages) { $ctrl.page = $ctrl.page + 1 } break; case 'last': $ctrl.page = $ctrl.pages break; case 'first': $ctrl.page = 1 break; } } $ctrl.pageChange = () => { if ($ctrl.page < 1) { $ctrl.page = 1 } else if ($ctrl.page > $ctrl.pages) { $ctrl.page = $ctrl.pages } } }; }) src/angular/factory/p3xr-redis-parser.js000066400000000000000000000151731520131260200205740ustar00rootroot00000000000000p3xr.ng.factory('p3xrRedisParser', function ($rootScope) { return new function () { const selfMain = this; this.array = (options) => { const {line} = options let {divider, fieldDivider} = options if (divider === undefined) { divider = ',' } if (fieldDivider === undefined) { fieldDivider = '=' } const rows = line.split(divider) const obj = {} for (let row of rows) { const rowLine = row.split(fieldDivider) obj[rowLine[0]] = rowLine[1].trim() } return obj } this.info = (str) => { const lines = str.split('\n') const obj = {} let section let currentSectionObj for (let line of lines) { if (line.startsWith('#')) { if (section !== undefined) { obj[section] = currentSectionObj } section = line.substring(1).toLowerCase().trim() currentSectionObj = {} } else if (line.length > 2) { const lineArray = line.split(':') currentSectionObj[lineArray[0]] = lineArray[1].includes(',') ? selfMain.array({ line: lineArray[1].trim() }) : lineArray[1].trim() } } if (section !== undefined) { obj[section] = currentSectionObj } if (obj.hasOwnProperty('keyspace')) { obj.keyspaceDatabases = {} Object.keys(obj.keyspace).forEach(key => { key = parseInt(key.substring(2)) obj.keyspaceDatabases[key] = true }) } return obj } this.keysToTreeControl = (options) => { // const start = Date.now() let {keys} = options let {divider} = options if (divider === undefined) { divider = p3xr.settings.redisTreeDivider } //console.warn(keys) const mainNodes = [] //console.log('expandedNodes', JSON.parse(JSON.stringify($rootScope.expandedNodes))) //$rootScope.expandedNodes = [] /* const newSavedExpandedNodes //FIXME saved expanded nodes is not working for (let saveExpandedNode of $rootScope.savedExpandedNodes) { if (saveExpandedNode.key === foundNode.key) { $rootScope.expandedNodes.push(foundNode) } } */ const newExpandedNodes = [] $rootScope.expandedNodes = [] const recursiveNodes = (splitKey, level = 0, nodes = mainNodes) => { let foundNode = false if (level + 1 < splitKey.length) { for (let nodeIndex in nodes) { const node = nodes[nodeIndex] if (node.label === splitKey[level] && node.type === 'folder') { foundNode = node } } } if (foundNode === false) { const defaultFoundNode = { label: splitKey[level], key: splitKey.slice(0, level + 1).join(divider), children: [], childCount: 0, } if (level + 1 === splitKey.length) { //console.warn(splitKey.length - 1 === level)t foundNode = Object.assign(defaultFoundNode, { type: 'element', keysInfo: p3xr.state.keysInfo[defaultFoundNode.key] }) } else { foundNode = Object.assign(defaultFoundNode, { type: 'folder', }) } nodes.push(foundNode) for (let saveExpandedNode of $rootScope.savedExpandedNodes) { if (saveExpandedNode.key === foundNode.key) { newExpandedNodes.push(foundNode) } } } if (level + 1 < splitKey.length) { recursiveNodes(splitKey, level + 1, foundNode.children) } } //console.log('newExpandedNodes', newExpandedNodes) $rootScope.expandedNodes = newExpandedNodes for (let key of keys) { let splitkey; if (divider === '') { splitkey = [key] } else { splitkey = key.split(divider) } recursiveNodes(splitkey) } const generatedKeys = {} const recursiveKeyCount = (node) => { generatedKeys[node.key] = node.children.length; for (let child of node.children) { recursiveKeyCount(child) } } for (let node of mainNodes) { recursiveKeyCount(node) } const recursiveCounterKeys = (node) => { for (let generatedKey of Object.keys(generatedKeys)) { if (generatedKey.startsWith(`${node.key}:`) || generatedKey === node.key) { node.childCount += generatedKeys[generatedKey] } } for (let child of node.children) { recursiveCounterKeys(child) } } for (let node of mainNodes) { recursiveCounterKeys(node) } //console.warn('key calculate', (Date.now() - start), 'ms' ) $rootScope.savedExpandedNodes = [] return mainNodes } this.console = new function () { const selfConsole = this; selfConsole.parse = (responseResult) => { if (typeof responseResult === 'object') { let result = '' Object.keys(responseResult).forEach(key => { if (result !== '') { result += "\n" } result += responseResult[key] }) return result } else { return responseResult } } } }; }); src/angular/factory/p3xr-socket.js000066400000000000000000000152671520131260200174700ustar00rootroot00000000000000p3xr.ng.factory('p3xrSocket', function ($rootScope, p3xrCommon, $state) { // socket.io now auto-configures its connection when we ommit a connection url const ioOptions = { rejectUnauthorized: false, path: '/socket.io', // transports: ['websocket'], secure: true, } if (global.p3xrDevMode === true ) { ioOptions.transports = ['websocket'] } /* // on reconnection, reset the transports option, as the Websocket // connection may have failed (caused by proxy, firewall, browser, ...) // https://socket.io/docs/client-api/ ioClient.on('reconnect_attempt', () => { ioClient.io.opts.transports = ['polling', 'websocket']; }); */ const ioClient = io.connect(p3xr.api.host, ioOptions); //console.warn(p3xr.api.host, ioOptions) let reconnect = false; ioClient.on('connect', async function () { if (reconnect) { console.log('p3xr-socket (socket) RE-connected', ioClient.id) //return; } else { console.log('p3xr-socket (socket) connected', ioClient.id) } reconnect = true; }) ioClient.on('disconnect', function () { location.reload() }) let donated = undefined ioClient.on('info-interval', (data) => { $rootScope.p3xr.state.donated = data.donated if (data.donated !== donated) { if (!global.p3xr.isBot()) { window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': p3xr.state.donated ? '/donated' : '/free' } ); } donated = data.donated $rootScope.$digest(); } }) let connectErrorWas = false const socketError = async function (error) { if (!connectErrorWas) { connectErrorWas = true; try { p3xrCommon.generalHandleError(error) $state.go('socketio-error', { error: error }) await p3xrCommon.confirm({ disableCancel: false, message: p3xr.strings.confirm.socketioConnectError }) location.reload() } catch (e) { p3xrCommon.generalHandleError(e) } } } ioClient.on('error', socketError) ioClient.on('connect_error', socketError) ioClient.on('connections', (data) => { //console.log(data) if (!p3xrCommon.generalHandleError(data)) { p3xr.connectionsReset() return; } p3xr.state.connections = data.connections $rootScope.$digest() }) ioClient.on('redis-disconnected', async (data) => { if ($rootScope.p3xr.state.connection !== undefined && $rootScope.p3xr.state.connection.id === data.connectionId) { $rootScope.p3xr.state.connection = undefined; if (data.status === 'error') { p3xrCommon.toast({ message: p3xr.strings.status.redisDisconnected(data) }) } else if (data.status === 'code') { if (!p3xr.strings.code.hasOwnProperty(data.code)) { p3xrCommon.toast({ message: `unknown redis disconnect code: ${data.code}` }) } else { p3xrCommon.toast({ message: p3xr.strings.code[data.code] }) } } $state.go('main') try { await request({ action: 'trigger-redis-disconnect', enableResponse: false, }) } catch (e) { p3xrCommon.generalHandleError(e) } //$rootScope.$digest(); } }) ioClient.on('redis-status', (data) => { $rootScope.p3xr.state.redisConnections = data.redisConnections setTimeout(() => { $rootScope.$digest() }) }) let receivedVersion = false ioClient.on('configuration', (data) => { $rootScope.p3xr.state.cfg = data; if (p3xr.state.cfg.snapshot === true) { p3xr.state.version = 'SNAPSHOT' } else { p3xr.state.version = 'v' + p3xr.state.cfg.version if (!receivedVersion) { receivedVersion = true window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': '/version/' + p3xr.state.version} ); } } $rootScope.$digest(); }) ioClient.on('error', p3xrCommon.generalHandleError) const request = (options) => { if (!options.payload) { options.payload = {} } if (typeof $rootScope.p3xr.state.search === 'string' && $rootScope.p3xr.state.search.length > 0) { if ($rootScope.p3xr.settings.searchStartsWith) { options.payload.match = $rootScope.p3xr.state.search + '*'; } else { options.payload.match = '*' + $rootScope.p3xr.state.search + '*'; } } options.payload.maxKeys = parseInt(p3xr.settings.maxKeys) let {enableResponse} = options if (enableResponse !== false) { enableResponse = true } if (enableResponse) { return new Promise((resolve, reject) => { options.requestId = p3xr.nextId(); const responseEvent = `p3xr-response-${options.requestId}` let timeout const response = (data) => { clearTimeout(timeout) ioClient.off(responseEvent) if (data.status === 'ok') { resolve(data) } else { const error = new Error(data.error) //error.code = data.error.code reject(error) } $rootScope.$digest() } timeout = setTimeout(() => { ioClient.off(responseEvent, response) reject(new Error(p3xr.strings.label.socketIoTimeout({ timeout: p3xr.settings.socket.timeout }))); $rootScope.$digest() }, p3xr.settings.socket.timeout) ioClient.on(responseEvent, response) ioClient.emit('p3xr-request', options) }) } else { ioClient.emit('p3xr-request', options) } } return { ioClient: ioClient, request: request, }; }); src/angular/injector.js000066400000000000000000000035521520131260200154460ustar00rootroot00000000000000//injector-angular-start require('./dialog/p3xr-dialog-connection.js'); require('./dialog/p3xr-dialog-json-editor.js'); require('./dialog/p3xr-dialog-json-view.js'); require('./dialog/p3xr-dialog-key-new-or-set.js'); require('./dialog/p3xr-dialog-treecontrol-settings.js'); require('./dialog/p3xr-dialog-ttl.js'); require('./directive/p3x-validate-json.js'); require('./directive/p3xr-ng-enter.js'); require('./factory/p3xr-common.js'); require('./factory/p3xr-key-paging.js'); require('./factory/p3xr-redis-parser.js'); require('./factory/p3xr-socket.js'); require('./layout/p3xr-layout.js'); require('./pages/main/key/p3xr-main-key-hash.js'); require('./pages/main/key/p3xr-main-key-list.js'); require('./pages/main/key/p3xr-main-key-set.js'); require('./pages/main/key/p3xr-main-key-stream.js'); require('./pages/main/key/p3xr-main-key-string.js'); require('./pages/main/key/p3xr-main-key-zset.js'); require('./pages/main/p3xr-main-key.js'); require('./pages/main/p3xr-main-statistics.js'); require('./pages/main/p3xr-main-treecontrol-controls.js'); require('./pages/main/p3xr-main-treecontrol.js'); require('./pages/p3xr-console.js'); require('./pages/p3xr-error.js'); require('./pages/p3xr-main.js'); require('./pages/p3xr-overview.js'); require('./pages/p3xr-settings.js'); require('./provider/p3xr-theme.js'); require('./provider/theme-generator/p3xr-theme-dark-neu.js'); require('./provider/theme-generator/p3xr-theme-dark.js'); require('./provider/theme-generator/p3xr-theme-darko-bluo.js'); require('./provider/theme-generator/p3xr-theme-enterprise.js'); require('./provider/theme-generator/p3xr-theme-light.js'); require('./provider/theme-generator/p3xr-theme-matrix.js'); require('./provider/theme-generator/p3xr-theme-redis.js'); require('./ui/p3xr-accordion.js'); require('./ui/p3xr-button.js'); require('./ui/p3xr-input.js'); require('./ui/p3xr-key-pager.js'); //injector-angular-endsrc/angular/layout/000077500000000000000000000000001520131260200146035ustar00rootroot00000000000000src/angular/layout/p3xr-layout.html000066400000000000000000000175521520131260200177120ustar00rootroot00000000000000
{{ $root.p3xr.state.version }}
{{ $root.p3xr.state.version }}
warning {{ $root.p3xr.strings.label.reducedFunction }}
src/angular/layout/p3xr-layout.js000066400000000000000000000222111520131260200173460ustar00rootroot00000000000000p3xr.ng.component('p3xrLayout', { template: require('./p3xr-layout.html'), controller: function (p3xrTheme, $rootScope, p3xrSocket, p3xrCommon, $state, $cookies, $timeout, $scope) { let themesCache this.getThemeKey = (themes) => { if (themesCache === undefined) { const themesKeys = Object.keys(themes) themesCache = themesKeys.sort((a, b) => { return themes[a].order - themes[b].order; }) } return themesCache } this.getVersionColor = () => { return p3xrTheme.getCurrentThemeName() === 'p3xrThemeMatrix' ? 'grey-900' : 'background-A100' } this.setTheme = (theme) => { p3xrTheme.setTheme(p3xrTheme.generateThemeName(theme)) } this.openLink = { github: () => { window.open(`https://github.com/patrikx3/redis-ui`, `github-patrikx3-redis-ui`) }, githubRelease: () => { window.open(`https://github.com/patrikx3/redis-ui/releases`, `github-patrikx3--redis-ui-releases`) }, githubChangelog: () => { window.open(`https://github.com/patrikx3/redis-ui/blob/master/change-log.md#change-log`, `github-patrikx3-redis-ui-changelog`) }, donate: () => { window.open(`https://www.paypal.me/patrikx3`, `p3x-redis-ui-donate`) }, } const camelCase = require('lodash/camelCase') Object.defineProperty(this, 'themeSelectedKey', { get: () => { let key = p3xr.state.theme key = key.slice('p3xrTheme'.length) key = camelCase(key) return key } }) let $warning const resize = () => { $warning.css('left', ((document.documentElement.clientWidth / 2) - ($warning.outerWidth() / 2)) + 'px') } this.reducedFunctionalty = () => { p3xrCommon.confirm({ disableCancel: true, message: p3xr.strings.label.tooManyKeys({ count: $rootScope.p3xr.state.keysRaw.length, maxLightKeysCount: p3xr.settings.maxLightKeysCount, }) }) } this.$onInit = () => { $warning = $('#p3xr-layout-reduced') resize() $window.on('resize', resize) const connection = $cookies.getObject(p3xr.settings.connectInfo.cookieName) if (connection !== undefined) { this.connect(connection) } $timeout(() => { global.p3xrSetLanguage = (key) => { $rootScope.$apply(() => { $rootScope.isElectron = true this.setLanguage(key) }) } global.p3xrSetMenu = (menu) => { $rootScope.$apply(() => { $rootScope.isElectron = true $state.go(menu) }) } }, 3000) /* $('head').append(` `) */ } this.$onDestroy = function () { $window.off('resize', resize) }; //let waitForGoogleTag //let waitedForGoogleTag = false //const maxWaitForGooglaTag = 4 * 5 if (!global.p3xr.isBot()) { $rootScope.$on('$locationChangeSuccess', async function (event, to, from) { const url = new URL(to) if (url.pathname.toLowerCase().startsWith('/main/key/')) { window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': '/main/key' } ); return } console.log('$locationChangeSuccess gtag', url.pathname) window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': url.pathname } ); }); } this.connect = async (connection, disableState = false) => { console.time('connect') //p3xr.state.search = ''; connection = angular.copy(connection) try { const originalStateArr = location.pathname.split('/') originalStateArr.shift() let originalState = originalStateArr.join('.') if (originalState === '') { originalState = 'main' } //console.warn(originalState) p3xr.ui.overlay.show({ message: p3xr.strings.title.connectingRedis }) const db = $cookies.get(p3xr.settings.connection.getCookieNameCurrentDatabase(connection.id)) const response = await p3xrSocket.request({ action: 'connection-connect', payload: { connection: connection, db: db }, }) $rootScope.p3xr.state.page = 1 p3xr.state.dbsize = response.dbsize let dbIndex = 0 const databaseIndexes = [] //console.warn(response) while (dbIndex < response.databases) { databaseIndexes.push(dbIndex++) } p3xr.state.commands = [] Object.keys(response.commands).forEach(key => { p3xr.state.commands.push(response.commands[key][0]) }) p3xr.state.commands.sort() $rootScope.p3xr.state.databaseIndexes = databaseIndexes $rootScope.p3xr.state.connection = connection p3xrCommon.loadRedisInfoResponse({ response: response }) $cookies.putObject(p3xr.settings.connectInfo.cookieName, connection, { expires: p3xr.settings.cookieExpiry }) //$state.go('main.statistics') //$state.reload(); if (disableState === true) { if (originalState.startsWith('main.key')) { originalState = 'main' } } if (!originalState.startsWith('main')) { $state.go(originalState) } else if (originalState === 'main') { $state.go('main.statistics') } } catch (error) { $cookies.remove(p3xr.settings.connectInfo.cookieName) $rootScope.p3xr.state.connection = undefined $state.go('main.statistics') p3xrCommon.generalHandleError(error) } finally { p3xr.ui.overlay.hide() } // $rootScope.$digest() console.timeEnd('connect') } this.disconnect = async () => { try { $cookies.remove(p3xr.settings.connectInfo.cookieName) await p3xrSocket.request({ action: 'connection-disconnect', payload: { connectionId: p3xr.state.connection.id, }, }) $rootScope.p3xr.state.connection = undefined } catch (error) { p3xrCommon.generalHandleError(error) } finally { $state.go('main') } // $rootScope.$digest() } Object.defineProperty(this, 'connectionName', { get: () => { if ($rootScope.p3xr.state.connection !== undefined) { return $rootScope.p3xr.strings.label.connected({ name: $rootScope.p3xr.state.connection.name }) } else { return $rootScope.p3xr.strings.intention.connect } } }) this.isMain = () => { return $state.current.name.startsWith('main') } this.isElectronInitialized = false this.setLanguage = async (key) => { try { $rootScope.p3xr.settings.language.current = key if ($rootScope.isElectron) { await p3xrSocket.request({ action: 'set-language', payload: { key: key, } }) this.isElectronInitialized = true $scope.$digest() } } catch (e) { p3xrCommon.generalHandleError(e) } } } }) src/angular/layout/p3xr-layout.scss000066400000000000000000000025451520131260200177150ustar00rootroot00000000000000@import '../../scss/vars'; .p3xr-layout-content, .p3xr-layout-content-electron { position: absolute; left: 0px; right: 0px; margin-bottom: $toolbar-height; } .p3xr-layout-content-electron { } .p3xr-layout-content { padding: $layout-padding; margin-top: $toolbar-height; } #p3xr-layout-header-container { top: 0px; } #p3xr-layout-footer-container { bottom: 0px; } #p3xr-layout-header-version-free { position: fixed; z-index: 6; top: 32px; left: 128px; font-size: 75%; } #p3xr-layout-header-version-donated { position: fixed; z-index: 6; top: 32px; left: 128px; font-size: 75%; } #p3xr-layout-header-container, #p3xr-layout-footer-container { position: fixed; z-index: 2; left: 0px; width: 100%; md-toolbar, .md-toolbar-tools { height: $toolbar-height !important; min-height: $toolbar-height !important; max-height: $toolbar-height !important; } } #p3xr-layout-reduced { position: fixed; z-index: 11; max-width: 310px; width: 310px; text-align: center; padding-left: 5px; padding-right: 5px; height: $toolbar-height / 2; bottom: $toolbar-height + 5px; font-weight: bold; text-transform: uppercase; line-height: $toolbar-height / 2; border-style: solid; border-width: 5px; cursor: pointer; } src/angular/pages/000077500000000000000000000000001520131260200143655ustar00rootroot00000000000000src/angular/pages/main/000077500000000000000000000000001520131260200153115ustar00rootroot00000000000000src/angular/pages/main/key/000077500000000000000000000000001520131260200161015ustar00rootroot00000000000000src/angular/pages/main/key/p3xr-main-key-hash.html000066400000000000000000000062341520131260200223210ustar00rootroot00000000000000
 {{ $root.p3xr.strings.page.key.hash.table.hashkey }}
{{ $root.p3xr.strings.page.key.hash.table.value }}
{{ $root.p3xr.strings.intention.add }} add
 {{ key.substring(0, $root.p3xr.settings.maxValueDisplay) }}...{{ key }}
{{ value.substring(0, $root.p3xr.settings.maxValueDisplay) }}...{{ value }}
{{ $root.p3xr.strings.intention.delete }} delete {{ $root.p3xr.strings.intention.jsonViewShow }} table_chart {{ $root.p3xr.strings.intention.copy }} content_copy {{ $root.p3xr.strings.intention.edit }} edit
src/angular/pages/main/key/p3xr-main-key-hash.js000066400000000000000000000062461520131260200217740ustar00rootroot00000000000000p3xr.ng.component('p3xrMainKeyHash', { template: require('./p3xr-main-key-hash.html'), bindings: { p3xrValue: '=', p3xrKey: '<', p3xrResponse: '<', }, controller: function (p3xrCommon, p3xrSocket, p3xrDialogJsonView, p3xrDialogKeyNewOrSet, $rootScope, $scope, p3xrKeyPaging) { const self = this const keyPaging = new p3xrKeyPaging({ $ctrl: self, $scope: $scope, }) this.$onInit = () => { keyPaging.figurePaging() } let values $scope.$watch('$ctrl.page', (n, o) => { values = {} const index = p3xr.settings.keyPageCount * (this.page - 1) let indexKeys = 0 for(let keys of Object.keys(this.p3xrValue)) { if (indexKeys >= index && indexKeys < index + p3xr.settings.keyPageCount) { values[keys] = this.p3xrValue[keys] } indexKeys++ } }) this.pageBasedList = () => { return values } this.copy = (opts) => { global.p3xr.clipboard({ value: opts.value }) p3xrCommon.toast(p3xr.strings.status.dataCopied) } this.addHash = async (options) => { try { await p3xrDialogKeyNewOrSet.show({ type: 'append', $event: options.$event, model: { type: 'hash', key: this.p3xrKey } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.deleteHashKey = async (options) => { try { await p3xrCommon.confirm({ event: options.$event, message: p3xr.strings.confirm.deleteHashKey, }) await p3xrSocket.request({ action: 'key-hash-delete-field', payload: { key: this.p3xrKey, hashKey: options.hashKey, } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.editValue = async (options) => { try { const {hashKey, value} = options await p3xrDialogKeyNewOrSet.show({ type: 'edit', $event: options.$event, model: { type: 'hash', value: value, hashKey: hashKey, key: this.p3xrKey } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.showJson = (options) => { const {value} = options; p3xrDialogJsonView.show({ value: value }) } } }) src/angular/pages/main/key/p3xr-main-key-list.html000066400000000000000000000056641520131260200223570ustar00rootroot00000000000000
  {{ $root.p3xr.strings.page.key.list.table.index }}
{{ $root.p3xr.strings.page.key.list.table.value }}
{{ $root.p3xr.strings.intention.add }} add
  {{ $index + ($ctrl.pages * ($ctrl.page -1) ) }}
{{ value.substring(0, $root.p3xr.settings.maxValueDisplay) }}...{{ value }}
{{ $root.p3xr.strings.intention.delete }} delete {{ $root.p3xr.strings.intention.jsonViewShow }} table_chart {{ $root.p3xr.strings.intention.copy }} content_copy {{ $root.p3xr.strings.intention.edit }} edit
src/angular/pages/main/key/p3xr-main-key-list.js000066400000000000000000000063701520131260200220220ustar00rootroot00000000000000p3xr.ng.component('p3xrMainKeyList', { template: require('./p3xr-main-key-list.html'), bindings: { p3xrValue: '=', p3xrKey: '<', p3xrResponse: '<', }, controller: function ($mdColors, p3xrCommon, p3xrSocket, $rootScope, p3xrDialogJsonView, p3xrDialogKeyNewOrSet, $scope, p3xrKeyPaging) { const self = this const keyPaging = new p3xrKeyPaging({ $ctrl: self, $scope: $scope, }) this.$onInit = () => { keyPaging.figurePaging() } let values $scope.$watch('$ctrl.page', (n, o) => { values = [] const index = p3xr.settings.keyPageCount * (this.page - 1) let indexKeys = 0 for(let valueIndex in this.p3xrValue) { if (indexKeys >= index && indexKeys < index + p3xr.settings.keyPageCount) { values.push(this.p3xrValue[valueIndex]) } indexKeys++ } }) this.pageBasedList = () => { return values } this.copy = (opts) => { global.p3xr.clipboard({ value: opts.value }) p3xrCommon.toast(p3xr.strings.status.dataCopied) } this.appendValue = async (options) => { try { const {index, value} = options await p3xrDialogKeyNewOrSet.show({ type: 'append', $event: options.$event, model: { type: 'list', key: this.p3xrKey } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.editValue = async (options) => { try { const {index, value} = options await p3xrDialogKeyNewOrSet.show({ type: 'edit', $event: options.$event, model: { type: 'list', value: value, index: options.index, key: this.p3xrKey } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.deleteListElement = async (options) => { try { await p3xrCommon.confirm({ event: options.$event, message: p3xr.strings.confirm.deleteListItem, }) const response = await p3xrSocket.request({ action: 'key-list-delete-index', payload: { key: this.p3xrKey, index: options.index, } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.showJson = (options) => { const {value} = options; p3xrDialogJsonView.show({ value: value }) } } }) src/angular/pages/main/key/p3xr-main-key-list.scss000066400000000000000000000000321520131260200223460ustar00rootroot00000000000000p3xr-main-key-list { } src/angular/pages/main/key/p3xr-main-key-set.html000066400000000000000000000050241520131260200221650ustar00rootroot00000000000000
{{ $root.p3xr.strings.page.key.set.table.value }}
{{ $root.p3xr.strings.intention.add }} add
{{ value.substring(0, $root.p3xr.settings.maxValueDisplay) }}...{{ value }}
{{ $root.p3xr.strings.intention.delete }} delete {{ $root.p3xr.strings.intention.jsonViewShow }} table_chart {{ $root.p3xr.strings.intention.copy }} content_copy {{ $root.p3xr.strings.intention.edit }} edit
src/angular/pages/main/key/p3xr-main-key-set.js000066400000000000000000000061561520131260200216440ustar00rootroot00000000000000p3xr.ng.component('p3xrMainKeySet', { template: require('./p3xr-main-key-set.html'), bindings: { p3xrValue: '=', p3xrKey: '<', p3xrResponse: '<', }, controller: function (p3xrCommon, p3xrSocket, p3xrDialogJsonView, p3xrDialogKeyNewOrSet, $rootScope, $scope, p3xrKeyPaging) { const self = this const keyPaging = new p3xrKeyPaging({ $ctrl: self, $scope: $scope, }) this.$onInit = () => { keyPaging.figurePaging() } let values $scope.$watch('$ctrl.page', (n, o) => { values = [] const index = p3xr.settings.keyPageCount * (this.page - 1) let indexKeys = 0 for(let valueIndex in this.p3xrValue) { if (indexKeys >= index && indexKeys < index + p3xr.settings.keyPageCount) { values.push(this.p3xrValue[valueIndex]) } indexKeys++ } }) this.pageBasedList = () => { return values } this.copy = (opts) => { global.p3xr.clipboard({ value: opts.value }) p3xrCommon.toast(p3xr.strings.status.dataCopied) } this.addSet = async (options) => { try { await p3xrDialogKeyNewOrSet.show({ type: 'append', $event: options.$event, model: { type: 'set', key: this.p3xrKey } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.deleteSetMember = async (options) => { try { await p3xrCommon.confirm({ event: options.$event, message: p3xr.strings.confirm.deleteSetMember, }) await p3xrSocket.request({ action: 'key-set-delete-member', payload: { key: this.p3xrKey, value: options.value, } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.editValue = async (options) => { try { const {value} = options await p3xrDialogKeyNewOrSet.show({ type: 'edit', $event: options.$event, model: { type: 'set', value: value, key: this.p3xrKey } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.showJson = (options) => { const {value} = options; p3xrDialogJsonView.show({ value: value }) } } }) src/angular/pages/main/key/p3xr-main-key-stream.html000066400000000000000000000040241520131260200226640ustar00rootroot00000000000000
 {{ $root.p3xr.strings.page.key.stream.table.timestamp }}
{{ $root.p3xr.strings.page.key.stream.table.field }} {{ $root.p3xr.strings.page.key.stream.table.value }}
{{ $root.p3xr.strings.intention.add }} add
{{ value[0] }} {{ $ctrl.showTimestamp({ timestamp: value[0]})}}
{{ dataArr[0]}} {{ dataArr[1]}}
{{ $root.p3xr.strings.intention.delete }} delete
src/angular/pages/main/key/p3xr-main-key-stream.js000066400000000000000000000064421520131260200223420ustar00rootroot00000000000000p3xr.ng.component('p3xrMainKeyStream', { template: require('./p3xr-main-key-stream.html'), bindings: { p3xrValue: '=', p3xrKey: '<', p3xrResponse: '<', }, controller: function ($scope, p3xrCommon, p3xrSocket, p3xrDialogJsonView, p3xrDialogKeyNewOrSet, $rootScope, p3xrKeyPaging) { const self = this const keyPaging = new p3xrKeyPaging({ $ctrl: self, $scope: $scope, watch: false, }) this.$onInit = () => { keyPaging.figurePaging() } let values $scope.$watch('$ctrl.page', (n, o) => { values = {} const index = p3xr.settings.keyPageCount * (this.page - 1) let indexKeys = 0 for(let keys of Object.keys(this.p3xrValue)) { if (indexKeys >= index && indexKeys < index + p3xr.settings.keyPageCount) { values[keys] = this.p3xrValue[keys] } indexKeys++ } }) this.pageBasedList = () => { return values } this.p3xrValueGenerated = [] $scope.$watch('$ctrl.p3xrValue', (n, o) => { this.p3xrValueGenerated = [] for(let value of this.p3xrValue) { const data = value[1] const result = [] for(let i = 0; i < data.length; i = i + 2) { result.push([ data[i], data[i + 1], ]) } this.p3xrValueGenerated.push(result) } keyPaging.figurePaging() }) this.copy = (opts) => { global.p3xr.clipboard({ value: opts.value }) p3xrCommon.toast(p3xr.strings.status.dataCopied) } this.addStream = async (options) => { try { await p3xrDialogKeyNewOrSet.show({ type: 'append', $event: options.$event, model: { type: 'stream', key: this.p3xrKey } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.deleteStreamTimestamp = async (options) => { try { await p3xrCommon.confirm({ event: options.$event, message: p3xr.strings.confirm.deleteStreamTimestamp, }) await p3xrSocket.request({ action: 'key-stream-delete-timestamp', payload: { key: this.p3xrKey, streamTimestamp: options.streamTimestamp, } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } const moment = require('moment') this.showTimestamp = ({ timestamp }) => { const dateNow = Number(timestamp.slice(0, timestamp.indexOf('-') )) const date = new Date(dateNow) return moment(date).format('L LTS') } } }) src/angular/pages/main/key/p3xr-main-key-string.html000066400000000000000000000107711520131260200227050ustar00rootroot00000000000000
table_chart {{ $root.p3xr.strings.intention.jsonViewShow }} {{ $root.p3xr.strings.intention.jsonViewShow }} content_copy {{ $root.p3xr.strings.intention.copy }} {{ $root.p3xr.strings.intention.copy }} format_line_spacing {{ $root.p3xr.strings.intention.formatJson }} {{ $root.p3xr.strings.intention.formatJson }} {{ $root.p3xr.strings.intention.jsonViewEditor }} {{ $root.p3xr.strings.intention.jsonViewEditor }} edit {{ $root.p3xr.strings.intention.edit }} {{ $root.p3xr.strings.intention.edit }}
{{ $root.p3xr.strings.label.validateJson }}
cancel {{ $root.p3xr.strings.intention.cancel }} {{ $root.p3xr.strings.intention.cancel }}
save {{ $root.p3xr.strings.intention.save }} {{ $root.p3xr.strings.intention.save }}
{{ $ctrl.p3xrValue.substring(0, $root.p3xr.settings.maxValueDisplay) }}...{{ $ctrl.p3xrValue }}
src/angular/pages/main/key/p3xr-main-key-string.js000066400000000000000000000057501520131260200223560ustar00rootroot00000000000000p3xr.ng.component('p3xrMainKeyString', { template: require('./p3xr-main-key-string.html'), bindings: { p3xrValue: '=', p3xrKey: '<', p3xrResponse: '<', }, controller: function (p3xrSocket, p3xrCommon, $rootScope, p3xrDialogJsonView, p3xrDialogJsonEditor) { this.copy = () => { global.p3xr.clipboard({ value: this.p3xrValue }) p3xrCommon.toast(p3xr.strings.status.dataCopied) } this.editable = false; let originalValue this.edit = () => { originalValue = angular.copy(this.p3xrValue) this.editable = true } this.cancelEdit = () => { this.p3xrValue = originalValue this.editable = false } this.validateJson = false this.save = async () => { try { if (this.validateJson === true) { try { JSON.parse(this.p3xrValue) } catch (e) { p3xrCommon.toast({ message: p3xr.strings.label.jsonViewNotParsable }) return; } } const response = await p3xrSocket.request({ action: 'key-set', payload: { type: this.p3xrResponse.type, value: this.p3xrValue, key: this.p3xrKey, } }) window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': '/key-set' } ); this.editable = false } catch (e) { p3xrCommon.generalHandleError(e) } finally { $rootScope.$broadcast('p3x-refresh-key'); } } this.jsonViewer = (options) => { p3xrDialogJsonView.show({ event: options.$event, value: this.p3xrValue }) // this.showJson = !this.showJson } this.jsonEditor = async(options) => { try { const result = await p3xrDialogJsonEditor.show({ event: options.$event, value: this.p3xrValue }) this.p3xrValue = result.obj await this.save() } catch(e) { p3xrCommon.generalHandleError(e) } // this.showJson = !this.showJson } this.formatJson = async () => { try { this.p3xrValue = JSON.stringify(JSON.parse(this.p3xrValue), null, p3xr.settings.jsonFormat) await this.save() } catch(e) { p3xrCommon.toast({ message: p3xr.strings.label.jsonViewNotParsable }) } } } }) src/angular/pages/main/key/p3xr-main-key-string.scss000066400000000000000000000001071520131260200227040ustar00rootroot00000000000000p3xr-main-key-string { textarea { width: 100%; } } src/angular/pages/main/key/p3xr-main-key-zset.html000066400000000000000000000056521520131260200223660ustar00rootroot00000000000000
  {{ $root.p3xr.strings.page.key.zset.table.score }}
{{ $root.p3xr.strings.page.key.zset.table.value }}
{{ $root.p3xr.strings.intention.add }} add
  {{ value[0] }}
{{ value[1].substring(0, $root.p3xr.settings.maxValueDisplay) }}...{{ value[1] }}
{{ $root.p3xr.strings.intention.delete }} delete {{ $root.p3xr.strings.intention.jsonViewShow }} table_chart {{ $root.p3xr.strings.intention.copy }} content_copy {{ $root.p3xr.strings.intention.edit }} edit
src/angular/pages/main/key/p3xr-main-key-zset.js000066400000000000000000000103531520131260200220300ustar00rootroot00000000000000p3xr.ng.component('p3xrMainKeyZset', { template: require('./p3xr-main-key-zset.html'), bindings: { p3xrValue: '=', p3xrKey: '<', p3xrResponse: '<', }, controller: function ($scope, p3xrCommon, p3xrSocket, p3xrDialogJsonView, p3xrDialogKeyNewOrSet, $rootScope, p3xrKeyPaging) { const self = this const keyPaging = new p3xrKeyPaging({ $ctrl: self, $scope: $scope, watch: false, figurePagingType: 'zset', }) this.$onInit = () => { keyPaging.figurePaging() } const onPage = (n, o) => { values = [] const index = p3xr.settings.keyPageCount * (this.page - 1) let indexKeys = 0 // console.warn(this.generatedValue) for(let valueIndex in this.generatedValue) { if (indexKeys >= index && indexKeys < index + p3xr.settings.keyPageCount) { values.push(this.generatedValue[valueIndex]) } indexKeys++ } } let values $scope.$watch('$ctrl.page', onPage) this.pageBasedList = () => { return values } this.copy = (opts) => { global.p3xr.clipboard({ value: opts.value }) p3xrCommon.toast(p3xr.strings.status.dataCopied) } const generateHashFromRedisSortedSet = (value,) => { const generatedValue = []; let savedValue = undefined; for (let item of value) { if (savedValue === undefined) { savedValue = item; } else { generatedValue.push([ parseFloat(item), savedValue ]) savedValue = undefined } } return generatedValue; } let lastVal $scope.$watch('$ctrl.p3xrValue', (newVal, oldVal) => { if (newVal !== lastVal) { //console.warn('p3xr main key zset update') lastVal = newVal this.generatedValue = generateHashFromRedisSortedSet(this.p3xrValue) keyPaging.figurePaging() onPage() } }) this.showJson = (options) => { const {value} = options; p3xrDialogJsonView.show({ value: value }) } this.addZSet = async (options) => { try { await p3xrDialogKeyNewOrSet.show({ type: 'append', $event: options.$event, model: { type: 'zset', key: this.p3xrKey } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.deleteZSet = async (options) => { try { await p3xrCommon.confirm({ event: options.$event, message: p3xr.strings.confirm.deleteZSetMember, }) await p3xrSocket.request({ action: 'key-zset-delete-member', payload: { key: this.p3xrKey, value: options.member, } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } this.editValue = async (options) => { try { const {member} = options await p3xrDialogKeyNewOrSet.show({ type: 'edit', $event: options.$event, model: { type: 'zset', score: options.score, value: member, key: this.p3xrKey } }) $rootScope.$broadcast('p3x-refresh-key'); } catch (e) { p3xrCommon.generalHandleError(e) } } } }) src/angular/pages/main/p3xr-main-key.html000066400000000000000000000143741520131260200206140ustar00rootroot00000000000000
delete {{ $root.p3xr.strings.intention.delete }} {{ $root.p3xr.strings.intention.delete }} timer {{ $root.p3xr.strings.intention.ttl }} {{ $root.p3xr.strings.intention.ttl }} {{ $root.p3xr.strings.label.ttlTitle }} fingerprint {{ $root.p3xr.strings.intention.rename }} {{ $root.p3xr.strings.intention.rename }} refresh {{ $root.p3xr.strings.intention.reloadKey }} {{ $root.p3xr.strings.intention.reloadKey }}

{{ $root.p3xr.strings.page.key.label.key }}: 

{{ $ctrl.$stateParams.key }}

{{ $root.p3xr.strings.page.key.label.ttl }}:

{{ $root.p3xr.strings.page.key.label.ttlNotExpire }}

{{ $root.p3xr.strings.page.key.label.ttl }}:
{{ $root.p3xr.strings.page.key.label.ttlNotExpire }} {{ $ctrl.response.ttl }}

{{ $root.p3xr.strings.page.key.label.type }}:

{{ $root.p3xr.strings.redisTypes[$ctrl.response.type] }}

{{ $root.p3xr.strings.page.key.label.encoding }}:

{{ $ctrl.response.encoding }}

{{ $root.p3xr.strings.page.key.label.length }}:

{{ $ctrl.charactersPrettyBytes($ctrl.response.length) }}   {{ $ctrl.response.length }}   {{ $root.p3xr.strings.page.key.label.lengthString }} {{ $root.p3xr.strings.page.key.label.lengthItem }}
src/angular/pages/main/p3xr-main-key.js000066400000000000000000000275161520131260200202660ustar00rootroot00000000000000//const moment = require("moment"); //const momentDurationFormatSetup = require("moment-duration-format"); let interval p3xr.ng.component('p3xrMainKey', { template: require('./p3xr-main-key.html'), bindings: { p3xrResize: '&', }, controller: function (p3xrCommon, p3xrRedisParser, p3xrSocket, $rootScope, $stateParams, $timeout, $scope, $mdDialog, $state, $interval, p3xrDialogTtl, p3xrTheme, $mdColors) { $interval.cancel(interval) this.$stateParams = $stateParams; let wasExpiring = false const checkTtl = () => { if (this.response.ttl < -1 || (wasExpiring && this.response.ttl < 1)) { p3xrCommon.toast({ message: p3xr.strings.status.keyIsNotExisting }) $interval.cancel(interval) p3xr.state.redisChanged = true $state.go('main.statistics') // $rootScope.$broadcast('p3x-refresh') return false } return true } const humanizeDuration = require("humanize-duration"); const loadTtl = () => { if (this.response.ttl > -1) { const actualTtl = () => { if (checkTtl()) { /* let years, months, days, hours, mins, seconds let diff diff = this.response.ttl * 1000; years = Math.floor((diff) / (1000 * 60 * 60 * 24 * 365)); diff = ((diff) % (1000 * 60 * 60 * 24 * 365)); months = Math.floor((diff) / (1000 * 60 * 60 * 24 * 30)); diff = ((diff) % (1000 * 60 * 60 * 24 * 30)); days = Math.floor((diff) / (1000 * 60 * 60 * 24)); diff = ((diff) % (1000 * 60 * 60 * 24)); hours = Math.floor((diff) / (1000 * 60 * 60)); diff = ((diff) % (1000 * 60 * 60)); mins = Math.floor((diff) / (1000 * 60)); diff = ((diff) / (1000 * 60)); seconds = Math.round((diff - mins) * 0.6 * 100); let duration = ''; if (years > 0) { duration += years + ' ' + (years === 1 ? $rootScope.p3xr.strings.time.year : $rootScope.p3xr.strings.time.years) duration += ', ' } if (months > 0) { duration += months + ' ' + (months === 1 ? $rootScope.p3xr.strings.time.month : $rootScope.p3xr.strings.time.months) duration += ', ' } if (days > 0) { duration += days + ' ' + (days === 1 ? $rootScope.p3xr.strings.time.day : $rootScope.p3xr.strings.time.days) duration += ', ' } duration += `${hours < 10 ? '0' + hours : hours}:${mins < 10 ? '0' + mins : mins}:${seconds < 10 ? '0' + seconds : seconds}`; this.ttlParsed = ' ' + duration */ let language switch(p3xr.settings.language.current) { case 'zn': language = 'zh_CN' break; default: language = 'en' break; } this.ttlParsed = ' ' + humanizeDuration(this.response.ttl * 1000, { language: language, delimiter: ' ', }) const counterEl = document.getElementById('p3xr-main-key-ttl-counter') if (counterEl) { counterEl.innerText = this.ttlParsed } } else { $interval.cancel(interval) } } actualTtl() if (!$rootScope.p3xr.state.reducedFunctions) { $interval.cancel(interval) interval = $interval(() => { this.response.ttl = this.response.ttl - 1 //console.log('aha', this.response.ttl) actualTtl() }, 1000) } } } const loadKey = async (options = {}) => { $interval.cancel(interval) let {withoutParent} = options if (withoutParent === undefined) { withoutParent = false } let hadError = undefined try { // it can throw an error, when we switch the database //p3xr.ui.overlay.show({ // message: p3xr.strings.intention.getKey //}) //const type = p3xr.state.keysInfo[$stateParams.key].type //console.warn('$stateParams.key', $stateParams.key) const response = await p3xrSocket.request({ action: 'key-get', payload: { key: $stateParams.key, //type: type, } }) this.response = response const type = response.type if (response.ttl === -2) { checkTtl() return; } switch (type) { case 'string': // console.warn(response) //p3xr.state.keysInfo[$stateParams.key].length = response.value.length response.length = response.value.length break; } if (response.ttl > -1) { wasExpiring = true } loadTtl() $scope.$digest() } catch (e) { hadError = e console.error(e) p3xrCommon.alert(p3xr.strings.label.unableToLoadKey({ key: $stateParams.key })) //p3xrCommon.generalHandleError(e) } finally { //p3xr.ui.overlay.hide() if (hadError !== undefined) { $state.go('main.statistics'); } else if (!withoutParent && $stateParams.resize !== null) { $stateParams.resize() } /* $timeout(() => { p3xr.ui.overlay.hide() }, p3xr.settings.debounce) */ } } const generateHighlight = () => { $('#p3xr-theme-styles-tree-key').remove() $('head').append('') } this.$onInit = () => { loadKey() generateHighlight() } $scope.$on('p3xr-theme-switched', generateHighlight) this.$onDestroy = function () { $('#p3xr-theme-styles-tree-key').remove() $interval.cancel(interval) }; this.charactersPrettyBytes = (length) => { if (length < 1024 || length === undefined) { return '' } const prettyBytes = require('pretty-bytes'); return '(' + prettyBytes(length) + ')' } this.refresh = async (options) => { window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': '/refresh' } ); await loadKey(options) $scope.$digest() } this.rename = async (opts) => { $rootScope.$broadcast('p3xr-key-rename', { key: $stateParams.key, $event: opts.$event, }); } this.delete = async (options) => { $rootScope.$broadcast('p3xr-key-delete', { key: $stateParams.key, event: options.$event, }); } this.setTtl = async (options) => { try { /* const confirm = $mdDialog.prompt() .title(p3xr.strings.confirm.ttl.title) .textContent(p3xr.strings.confirm.ttl.textContent) .placeholder(p3xr.strings.confirm.ttl.placeholder) .ariaLabel(p3xr.strings.confirm.ttl.placeholder) .initialValue(this.response.ttl === -1 ? '' : this.response.ttl) .targetEvent(options.$event) .ok(p3xr.strings.intention.ttl) .cancel(p3xr.strings.intention.cancel); */ // const confirmResponse = await $mdDialog.show(confirm) const confirmResponse = await p3xrDialogTtl.show({ $event: options.$event, model: { ttl: this.response.ttl === -1 ? '' : this.response.ttl } }) // console.error('confirmResponse', confirmResponse) // console.error('String(confirmResponse.model.ttl).trim()', String(confirmResponse.model.ttl).trim()) if (confirmResponse === undefined) { return } if (confirmResponse.model.ttl == null || String(confirmResponse.model.ttl).trim() === '') { const response = await p3xrSocket.request({ action: 'persist', payload: { key: $stateParams.key, } }) window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': '/persist' } ); await this.refresh() p3xrCommon.toast({ message: p3xr.strings.status.persisted }) } else if (!String(confirmResponse.model.ttl).match(/^-{0,1}\d+$/)) { p3xrCommon.toast({ message: p3xr.strings.status.notInteger }) } else { const response = await p3xrSocket.request({ action: 'expire', payload: { key: $stateParams.key, ttl: parseInt(confirmResponse.model.ttl), } }) window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': '/expire' } ); await this.refresh() p3xrCommon.toast({ message: p3xr.strings.status.ttlChanged }) } } catch (e) { p3xrCommon.generalHandleError(e) } } // const refreshDebounced = debounce(this.refresh, 1000) $scope.$on('p3x-refresh', () => { this.refresh({ withoutParent: true }) }) $scope.$on('p3x-refresh-key', () => { this.refresh({ withoutParent: true }) }) } }) src/angular/pages/main/p3xr-main-key.scss000066400000000000000000000003021520131260200206050ustar00rootroot00000000000000p3xr-main-key { .p3xr-main-key-label-key-title { cursor: pointer; font-weight: bold; } md-list-item { p { font-weight: bold; } } } src/angular/pages/main/p3xr-main-statistics.html000066400000000000000000000027501520131260200222110ustar00rootroot00000000000000

{{ $ctrl.generateKey(itemKey) }}

{{ itemValue }}

{{ $ctrl.generateKey(itemKey) }}

{{ itemValue }}
src/angular/pages/main/p3xr-main-statistics.js000066400000000000000000000060571520131260200216650ustar00rootroot00000000000000p3xr.ng.component('p3xrMainStatistics', { template: require('./p3xr-main-statistics.html'), controller: function (p3xrCommon, p3xrRedisParser, p3xrSocket, $rootScope, $scope, $timeout, $stateParams, $mdMedia) { const exclude = ['in', 'run', 'per'] const include = ['sha1',] const replace = { 'perc': 'percent', 'sec': 'seconds' } //const $container = let isXsmall = true const resize = () => { //console.log('container', $container, $container[0].offsetHeight) if (isXsmall) { this.maxHeight = 'auto' } else { this.maxHeight = document.getElementById('p3xr-main-content-container').offsetHeight - 50 } } $scope.$watch(() => $mdMedia('xs'), (newVal, oldVal) => { isXsmall = newVal resize() }) $window.on('resize', resize) this.$doCheck = resize this.$onInit = () => { if (p3xr.state.redisChanged) { p3xr.state.redisChanged = false $rootScope.$broadcast('p3x-refresh') } } this.$onDestroy = () => { $window.off('resize', resize) } this.hasDatabases = Object.keys($rootScope.p3xr.state.info.keyspaceDatabases).length > 0 //console.warn(p3xr.state.info) this.generateKey = (key) => { if (p3xr.strings.title.hasOwnProperty(key)) { return p3xr.strings.title[key] } const keyElem = key.split('_').map((instance, index) => { if (replace.hasOwnProperty(instance)) { instance = replace[instance] } if (include.includes(instance) || (instance.length < 4 && !exclude.includes(instance))) { return instance.toUpperCase() } else if (index === 0) { return instance[0].toUpperCase() + instance.substring(1) } return instance }) return keyElem.join(' ') } //FIXME disable hacking on the tab /* $scope.$on('p3x-refresh-statistics-tabs', () => { $timeout(() => { p3xr.state.info.hack = { hack: 'hacking' } this.hasDatabases = Object.keys($rootScope.p3xr.state.info.keyspaceDatabases).length > 0 $timeout(() => { delete p3xr.state.info.hack; $rootScope.$digest(); }) }) }) */ /* console.warn('$stateParams', $stateParams, $stateParams.action) if ($stateParams.action && $stateParams.action === 'reload-delete') { // $rootScope.savedExpandedNodes = $stateParams.expandedNodes console.log($stateParams.expandedNodes) $rootScope.$broadcast('p3x-refresh') //p3xrCommon.loadRedisInfoResponse({response: $stateParams.response}) } */ } }) src/angular/pages/main/p3xr-main-statistics.scss000066400000000000000000000000661520131260200222160ustar00rootroot00000000000000#p3xr-main-statistics-dbs { border-radius: 0px; } src/angular/pages/main/p3xr-main-treecontrol-controls.html000066400000000000000000000126421520131260200242210ustar00rootroot00000000000000
{{ $root.p3xr.strings.page.treeControls.expandAll}} keyboard_arrow_down {{ $root.p3xr.strings.page.treeControls.collapseAll}} keyboard_arrow_up {{ $root.p3xr.strings.intention.refresh}} refresh {{ $root.p3xr.strings.form.treeSettings.label.formName}} settings {{ $root.p3xr.strings.form.treeSettings.field.treeSeparator }} {{ divider }} {{ $root.p3xr.strings.form.treeSettings.field.treeSeparatorSelector }}
{{ $root.p3xr.strings.status.keyCount({keyCount: $root.p3xr.state.keysRaw.length }) }} {{ $root.p3xr.strings.page.treeControls.pager.first}} skip_previous {{ $root.p3xr.strings.page.treeControls.pager.prev}} keyboard_arrow_left / {{ $root.p3xr.state.pages }} {{ $root.p3xr.strings.page.treeControls.pager.next}} keyboard_arrow_right {{ $root.p3xr.strings.page.treeControls.pager.last}} skip_next {{ $root.p3xr.strings.status.keyCount({keyCount: $root.p3xr.state.keysRaw.length }) }}  src/angular/pages/main/p3xr-main-treecontrol-controls.js000066400000000000000000000123661520131260200236740ustar00rootroot00000000000000p3xr.ng.component('p3xrMainTreecontrolControls', { template: require('./p3xr-main-treecontrol-controls.html'), bindings: { p3xrMainRef: '<' }, controller: function ($cookies, $rootScope, p3xrCommon, $timeout, p3xrDialogTreecontrolSettings, $scope) { this.treeExpandAll = () => { try { $rootScope.$broadcast('p3xr-main-treecontrol', false) p3xr.ui.overlay.show({ message: p3xr.strings.status.treeExpandAll }) let expandedNodes = [] /* require('../../../core/node-inview-recursive').recursive({ status: false, nodes: $rootScope.keysTreeRendered, nodeCallback: (opts) => { const { node } = opts if (node.type === 'folder') { expandedNodes.push(node) } } }) */ //FIXME use with general recursive solution, as above (just not working, too tired) const recursiveFolders = (node, level = 0) => { delete node.$inview if (node.type === 'folder') { expandedNodes.push(node) for (let childNode of node.children) { recursiveFolders(childNode, level++) } } } for (let node of $rootScope.keysTreeRendered) { recursiveFolders(node) } $rootScope.expandedNodes = expandedNodes } catch (e) { p3xrCommon.generalHandleError(e) } finally { p3xr.ui.overlay.hide() $timeout(() => { $rootScope.$broadcast('p3xr-main-treecontrol', true) }) } } this.treeCollapseAll = () => { $rootScope.$broadcast('p3xr-main-treecontrol', false) $rootScope.expandedNodes = [] $timeout(() => { $rootScope.$broadcast('p3xr-main-treecontrol', true) }) } this.page = (options) => { const {page} = options ///console.log(page ) switch (page) { case 'prev': if ($rootScope.p3xr.state.page - 1 >= 1) { $rootScope.p3xr.state.page = $rootScope.p3xr.state.page - 1 } break; case 'next': if ($rootScope.p3xr.state.page + 1 <= $rootScope.p3xr.state.pages) { $rootScope.p3xr.state.page = $rootScope.p3xr.state.page + 1 } break; case 'last': $rootScope.p3xr.state.page = $rootScope.p3xr.state.pages break; case 'first': $rootScope.p3xr.state.page = 1 break; } $timeout(() => { $rootScope.$digest() }) } this.pageChange = () => { if ($rootScope.p3xr.state.page < 1) { $rootScope.p3xr.state.page = 1 } else if ($rootScope.p3xr.state.page > $rootScope.p3xr.state.pages) { $rootScope.p3xr.state.page = $rootScope.p3xr.state.pages } } this.openTreeSettingDialog = (opts) => { opts.p3xrMainRef = this.p3xrMainRef p3xrDialogTreecontrolSettings.show(opts); //console.warn($rootScope.p3xr.state.redisTreeDivider) } this.search = '' this.$onInit = () => { this.search = $rootScope.p3xr.state.search } //console.warn($rootScope.p3xr.state.search) this.onSearchChange = () => { // $rootScope.p3xr.state.search = this.search if ($rootScope.p3xr.settings.searchClientSide) { // $rootScope.p3xr.settings.searchClientSide // $rootScope.p3xr.settings.searchStartsWith $rootScope.p3xr.state.redisChanged = true } else { this.p3xrMainRef.refresh() } $rootScope.p3xr.state.page = 1; } this.treeDividerChange = () => { $rootScope.p3xr.state.redisChanged = true // this.p3xrMainRef.refresh() $rootScope.$broadcast('p3x-refresh'); } /* this.dividerSelectStatus = (show) => { if (show === true) { console.log('dividerSelectStatus show', show) const input = $('#p3xr-main-treecontrol-controls-tree-divider-input') const offset = input.offset() const container = $('.p3xr-main-treecontrol-controls-divider-select-container') const top = offset.top + input.height() const left = offset.left container[0].style.top = `${top}px` container[0].style.left = `${left}px` console.log(offset, input.height(), container[0].style.top, container[0].style.left, top, left) } } */ } }) src/angular/pages/main/p3xr-main-treecontrol-controls.scss000066400000000000000000000032001520131260200242160ustar00rootroot00000000000000p3xr-main-treecontrol-controls { margin-top: 2px; display: block; text-align: center; min-height: 24px; .md-icon-button { height: auto !important; min-height: auto !important;; width: auto !important;; min-width: auto !important;; margin: 0 !important;; padding: 0 !important; } .p3xr-main-treecontrol-controls-search { clear: both; text-align: left; padding: 5px; input.withSearch { width: calc(100% - 100px) !important; } input.withoutSearch { width: calc(100% - 80px) !important; } } } .p3xr-main-treecontrol-controls-divider-select { display: inline-block; .md-select-value { span:not(.md-select-icon) { visibility: hidden !important; display: none !important; } min-width: 0px !important; min-height: 0px !important; .md-select-icon { width: 3px !important; position: relative; left: -8px; top: -2px; } } } .p3xr-main-treecontrol-controls-divider-select-container { font-family: 'Roboto Mono' !important; font-weight: 500; font-size: 14px; padding: 0px !important; top: 137px !important; left: 103px !important; md-select-menu { md-content { min-width: auto; } } } .p3xr-main-treecontrol-controls-pager { position: relative; display: inline-block; top: 2px; } .p3xr-main-treecontrol-controls-keycount { opacity: 0.5; float: right; line-height: 26px; margin-top: 6px; } src/angular/pages/main/p3xr-main-treecontrol.html000066400000000000000000000104151520131260200223540ustar00rootroot00000000000000 {{ $ctrl.extractNodeTooltip(node) }} {{ $root.p3xr.strings.confirm.deleteAllKeys({key: node.key}) }} close {{ $root.p3xr.strings.intention.delete }} close {{ $root.p3xr.strings.intention.addKey }} add src/angular/pages/main/p3xr-main-treecontrol.js000066400000000000000000000221351520131260200220260ustar00rootroot00000000000000p3xr.ng.component('p3xrMainTree', { template: require('./p3xr-main-treecontrol.html'), bindings: { p3xrResize: '&', p3xrMainRef: '<' }, controller: function (p3xrCommon, p3xrRedisParser, p3xrSocket, $rootScope, $timeout, $state, $scope, $mdDialog, p3xrDialogKeyNewOrSet, p3xrTheme, $stateParams) { /* this.$onInit = () => { this.p3xrResize() $rootScope.$broadcast('p3x-resize') } */ /* let check = 0 this.$doCheck = () => { if (check < 10) { check++ // console.log('resize for tree') this.p3xrMainRef.resizeRaw() // $rootScope.$broadcast('p3x-resize') } } */ /* this.$onChanges = (changesObj) => { $rootScope.$broadcast('p3x-resize') } this.$postLink = () => { $rootScope.$broadcast('p3x-resize') } */ this.displayNode = (node, $inview) => { node.$inview = $inview } this.getTreeTheme = () => { if (!p3xrTheme.isDark()) { return 'tree-classic' } return 'tree-dark' } this.keysTreeOptions = { nodeChildren: "children", dirSelectable: false, multiSelection: false, /* injectClasses: { ul: "a1", li: "a2", liSelected: "a7", iExpanded: "a3", iCollapsed: "a4", iLeaf: "a5", label: "a6", labelSelected: "a8" } */ }; this.selectTreeNode = function (node, selected, $parentNode, $index, $first, $middle, $last, $odd, $even, $path) { //console.warn('selectTreeNode', arguments) $state.go('main.key', { key: node.key, resize: this.p3xrResize, }) } this.showToggle = function (node, expanded, $parentNode, $index, $first, $middle, $last, $odd, $even, $path) { if (!expanded) { require('../../../core/node-inview-recursive').recursive({ nodes: $rootScope.keysTreeRendered, }) } $rootScope.$broadcast('p3xr-main-treecontrol-control-noop') // console.warn('showToggle', arguments, $path()) /* p3xrCommon.toast({ message: 'key ' + node.key }) */ } this.delete = async (options) => { try { options.event.preventDefault() options.event.stopPropagation() await p3xrCommon.confirm({ event: options.$event, message: p3xr.strings.confirm.deleteKey }) //const expandedNodes = angular.copy($rootScope.expandedNodes); await p3xrSocket.request({ action: 'delete', payload: { key: options.key } }) window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': '/delete' } ); /* $timeout(() => { $rootScope.savedExpandedNodes = expandedNodes p3xrCommon.loadRedisInfoResponse({response: response}) }) */ /* const params = { action: 'reload-delete', expandedNodes: expandedNodes, response: expandedNodes, } */ //console.log('delete params', params) $state.go('main.statistics' /*, params*/) p3xrCommon.toast({ message: p3xr.strings.status.deletedKey({ key: options.key }) }) await this.p3xrMainRef.refresh() } catch (e) { p3xrCommon.generalHandleError(e) } } this.rename = async (options) => { try { const confirm = $mdDialog.prompt() .title(p3xr.strings.confirm.rename.title) .textContent(p3xr.strings.confirm.rename.textContent) .placeholder(p3xr.strings.confirm.rename.placeholder) .ariaLabel(p3xr.strings.confirm.rename.placeholder) .initialValue(options.key) .targetEvent(options.$event) .required(true) .ok(p3xr.strings.intention.rename) .cancel(p3xr.strings.intention.cancel); const confirmResponse = await $mdDialog.show(confirm) await p3xrSocket.request({ action: 'rename', payload: { key: options.key, keyNew: confirmResponse, } }) window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': '/rename' } ); $state.go('main.key', { key: confirmResponse, resize: this.p3xrResize, }) p3xrCommon.toast({ message: p3xr.strings.status.renamedKey }) await this.p3xrMainRef.refresh() } catch (e) { p3xrCommon.generalHandleError(e) } } this.deleteTree = async (options) => { try { const {event, node} = options // event.preventDefault() event.stopPropagation(); await p3xrCommon.confirm({ event: event, message: p3xr.strings.confirm.deleteAllKeys({ key: node.key }) }) await p3xrSocket.request({ action: 'key-del-tree', payload: { key: node.key, redisTreeDivider: p3xr.settings.redisTreeDivider } }) p3xrCommon.toast({ message: p3xr.strings.status.treeDeleted({ key: node.key }) }) if ($stateParams.key !== undefined && $stateParams.key.startsWith(node.key + p3xr.settings.redisTreeDivider)) { $state.go('main.statistics') } await this.p3xrMainRef.refresh() } catch (e) { p3xrCommon.generalHandleError(e) } } this.addKey = async (options) => { const {event, node} = options event.stopPropagation(); try { const response = await p3xrDialogKeyNewOrSet.show({ $event: event, node: node, type: 'add', }) await this.p3xrMainRef.refresh() $state.go('main.key', { key: response.key, resize: this.p3xrResize, }) } catch (e) { p3xrCommon.generalHandleError(e) } } this.extractNodeTooltip = (node) => { if (node.type !== 'folder' && node.keysInfo !== undefined) { if (node.keysInfo === undefined) { return ''; } return p3xr.ui.htmlEncode(p3xr.strings.redisTypes[node.keysInfo.type] + ' - ' + node.key) } return p3xr.ui.htmlEncode(node.key) } this.extractNodeKey = (node) => { if (node.type === 'folder') { return '' } return p3xr.ui.htmlEncode(node.key) } $scope.$on('p3xr-key-delete', (event, arg) => { this.delete(arg) }); $scope.$on('p3xr-key-rename', (event, arg) => { this.rename(arg) }); $scope.$on('p3xr-key-new', (event, arg) => { this.addKey(arg) }); $scope.$on('p3xr-main-treecontrol', (event, arg) => { this.isEnabled = arg }); this.hover = ({node}) => { if (p3xr.state.connection.readonly === true) { return } node.show = true } this.isEnabled = true const focusListener = () => { if (this.isEnabled === true) { this.isEnabled = false $timeout(() => { this.isEnabled = true }) } } window.addEventListener('focus', focusListener) $scope.$on('$destroy', () => { window.removeEventListener('focus', focusListener) }) } }) src/angular/pages/main/p3xr-main-treecontrol.scss000066400000000000000000000036761520131260200223760ustar00rootroot00000000000000p3xr-main { .p3xr-main-treecontrol-node-icon { display: inline-block; min-width: 12px; text-align: center; } treecontrol > ul > li.tree-expanded > i.tree-branch-head, treecontrol > ul > li.tree-collapsed > i.tree-branch-head { margin-left: 4px !important; margin-right: 4px !important; white-space: nowrap !important; } treecontrol li.tree-expanded > i.tree-branch-head, treecontrol li.tree-collapsed > i.tree-branch-head { display: inline-block; background-image: none !important; font-family: 'Font Awesome 5 Free'; font-style: normal; font-weight: 900; font-size: 15px; padding: 0 !important; // margin-left: 10px !important; // margin-left: 8px !important; line-height: 20px; min-width: 12px; text-align: center; } treecontrol li { white-space: nowrap; } treecontrol li.tree-collapsed > i.tree-branch-head:before { content: "\f07b"; } treecontrol li.tree-expanded > i.tree-branch-head:before { content: "\f07c"; } treecontrol { ul { overflow: visible !important; /*# STEP1 #### Override overflow attribute like uncledb said */ } .tree-leaf-head { display: none !important; background-image: none; } } treecontrol > ul > li { padding-left: 4px; } treecontrol .tree-label:focus, treecontrol .tree-label.tree-selected { outline: none; font-weight: 500; background: none; } .p3xr-main-tree { .p3xr-main-tree-node { cursor: pointer; line-height: 28px !important; white-space: nowrap; /*# STEP-2 #Set nowrap for node labels ###### THIS DID THE TRICK FOR ME ########*/ .p3xr-main-tree-node-count { opacity: 0.5; } } } } src/angular/pages/p3xr-console.html000066400000000000000000000036371520131260200176200ustar00rootroot00000000000000

{{ $root.p3xr.strings.label.console }}

{{ $root.p3xr.strings.intention.pubsubMonitor }} {{ $root.p3xr.strings.intention.pubsubMonitor }}
{{item}} src/angular/pages/p3xr-console.js000066400000000000000000000261351520131260200172660ustar00rootroot00000000000000let actionHistoryPosition = -1 const htmlEncode = global.htmlEncode; //localStorage.setItem('console-history', '[]') p3xr.ng.component('p3xrConsole', { template: require('./p3xr-console.html'), controller: function (p3xrCommon, p3xrSocket, $state, $rootScope, p3xrRedisParser, $mdDialog, $timeout, $scope) { // .p3xr-layout-footer-container // .p3xr-layout-header-container // #p3xr-console-header // #p3xr-console-input // $window.height() const getActionHistory = () => { return JSON.parse(localStorage.getItem('console-history') || "[]"); } const redisCommands = p3xr.state.commands let $container let $header; let $footer; let $consoleHeader let $input let $output let scrollers if (!$rootScope.hasConnected()) { $state.go('main') } const debounce = require('lodash/debounce') const rawResize = () => { let minus = 0 let $components //if ($rootScope.isElectron) { // $components = [$footer, $consoleHeader] //} else { $components = [$header, $footer, $consoleHeader] //} for (let item of $components) { minus += item.outerHeight() } const windowHeight = $window.height() //console.log(windowHeight, minus) const adjustments = 70 const outputHeight = Math.max(windowHeight - minus - adjustments, 0) $container.height(outputHeight) $container.css('max-height', `${outputHeight}px`) } const resize = debounce(rawResize, p3xr.settings.debounce) /* let resizeObserver = new ResizeObserver(entries => { console.log('ResizeObserver', entries) rawResize() }) */ /* let check = 0 this.$doCheck = () => { if (check < 10) { check++ // console.log('resize for tree') rawResize() // $rootScope.$broadcast('p3x-resize') } } */ const onPubSubMessage = (data) => { //console.warn('pub-sub', data) if (p3xr.state.monitor === false) { return } let message = htmlEncode(String(data.message)) $output.append(`PubSub channel: ${data.channel}`) $output.append(`
${message}

`) scrollers.scrollTop = scrollers.scrollHeight; } this.$onInit = () => { $container = $('#p3xr-console-content') $header = $('#p3xr-layout-header-container') $footer = $('#p3xr-layout-footer-container') $consoleHeader = $('#p3xr-console-header') $output = $('#p3xr-console-content-output') scrollers = $container[0] $window.on('resize', resize) resize() p3xrSocket.ioClient.on('pubsub-message', onPubSubMessage) setTimeout(() => { $input = $('#p3xr-console-input') $input.on('keydown', this.action) /* md-colors="{'border-color': $ctrl.inputBorderColor()}" ng-style="{ 'background': $ctrl.inputBackground(), 'color': $ctrl.inputColor()}" this.inputBackground = () => { return p3xrTheme.isDark() ? 'rgba(64, 64, 64, 1)' : 'white' } this.inputBorderColor = () => { return p3xrTheme.isDark() ? 'primary-hue-1' : 'primary-hue-1' } this.inputColor = () => { return p3xrTheme.isDark() ? 'white' : 'black' } */ this.setTheme() this.clearConsole() }) } this.setTheme = () => { const css = { borderColor: p3xrCommon.inputBorderColor(), backgroundColor: p3xrCommon.inputBackground(), color: p3xrCommon.inputColor(), } //console.warn('dark', p3xrTheme.isDark(), css) $input.css(css) } $scope.$on('p3xr-theme-switched', () => { this.setTheme() }) this.$postLink = () => { rawResize() } this.$onDestroy = function () { $window.off('resize', resize) p3xrSocket.ioClient.removeListener('pubsub-message', onPubSubMessage) }; //this.inputValue = '' this.actionEnter = async (inputValue) => { var $acElement = angular.element(document.getElementById('p3xr-console-autocomplete')); var acCtrl = $acElement.controller('mdAutocomplete'); acCtrl.hidden = true; let response; const enter = String(inputValue).trim() if (enter === '') { return; } try { $output.append(`
${enter}
`) response = await p3xrSocket.request({ action: 'console', payload: { command: enter } }) //console.warn(typeof response.result, response.result, response.generatedCommand) const result = htmlEncode(String(p3xrRedisParser.console.parse(response.result))) //console.log(result) $output.append(`
${result}
`) if (response.hasOwnProperty('database')) { $rootScope.p3xr.state.currentDatabase = response.database $rootScope.p3xr.state.redisChanged = true } $scope.searchText = '' $scope.$digest() } catch (e) { console.error(e) $output.append(`
${p3xr.strings.code[e.message] || e.message}
`) } finally { let history if (response !== undefined) { history = response.generatedCommand } else { history = enter } let actionHistory = getActionHistory() const actionHistoryIndexOf = actionHistory.indexOf(history) if (actionHistoryIndexOf > -1) { actionHistory.splice(actionHistoryIndexOf, 1) } actionHistory.push(history) if (actionHistory.length > 20) { actionHistory = actionHistory.slice(0, 20) } localStorage.setItem('console-history', JSON.stringify(actionHistory)) actionHistoryPosition = -1 // //console.log(scrollers.scrollHeight, scrollers.scrollTop, scrollers.height) scrollers.scrollTop = scrollers.scrollHeight; $output.scrollTop($output.prop("scrollHeight")); // //$input.focus() } } this.action = ($event) => { switch ($event.keyCode) { // keyup 38 case 38: { $event.preventDefault() $event.stopPropagation() const actionHistory = getActionHistory() if (actionHistory.length < 1) { return; } if (actionHistoryPosition === -1) { actionHistoryPosition = actionHistory.length } actionHistoryPosition-- if (actionHistoryPosition < 0) { actionHistoryPosition = actionHistory.length - 1 } $scope.searchText = actionHistory[actionHistoryPosition] break; } // keydown 40 case 40: { $event.preventDefault() $event.stopPropagation() const actionHistory = getActionHistory() if (actionHistory.length < 1) { return; } actionHistoryPosition++ if (actionHistoryPosition >= actionHistory.length) { actionHistoryPosition = 0 } $scope.searchText = actionHistory[actionHistoryPosition] break; } default: actionHistoryPosition = -1 break; } const log = getActionHistory() //console.log('actionHistoryPosition', actionHistoryPosition, 'getActionHistory()', 'log', log, 'log.length', log.length) } this.clearConsole = () => { $output.empty() $output.append('
' + $rootScope.p3xr.strings.label.welcomeConsole + '
') $output.append('
' + $rootScope.p3xr.strings.label.welcomeConsoleInfo + '
') $output.append('
') $input.focus() } this.getMatches = (searchText) => { return redisCommands.filter(e => e.includes(searchText)) } this.commands = (options) => { $mdDialog.show({ controller: function ($scope, $mdDialog) { $scope.ok = function () { $mdDialog.hide(); }; $scope.$watch(function () { const height = $('#p3xr-console-commands').parent().height(); return height; }, (newValue, oldValue) => { $scope.height = newValue; }) }, fullscreen: true, targetEvent: options.$event, template: `
keyboard   {{ $root.p3xr.strings.intention.commands }} close
close {{ $root.p3xr.strings.intention.close }}
`, }); } } }) src/angular/pages/p3xr-console.scss000066400000000000000000000022241520131260200176160ustar00rootroot00000000000000@import '../../scss/vars'; p3xr-console { .p3xr-console-electron { margin: $layout-padding; } #p3xr-console-content { font-family: 'Roboto Mono' !important; //font-weight: 500; $minWidthCalc: 20px; text-align: center; #p3xr-console-content-output { pre { font-family: 'Roboto Mono' !important; //font-weight: 500; white-space: pre-wrap; } min-width: calc(100% - #{$minWidthCalc}); text-align: left; .p3xr-console-content-output-item:before { content: "> "; opacity: 0.5; } } } } @import '../ui/p3xr-input'; #p3xr-console-input { @import '../ui/p3xr-input'; @extend .p3xr-input; min-width: calc(100% - 9px); position: fixed; bottom: $toolbar-height + 8px; left: 3px; right: 0px; } #p3xr-console-input:focus { @extend .p3xr-input:focus; } .p3xr-console { background-color: transparent !important; md-autocomplete-wrap { box-shadow: none; background: none !important; } } src/angular/pages/p3xr-error.html000066400000000000000000000010211520131260200172700ustar00rootroot00000000000000

{{ $root.p3xr.strings.title.socketioConnectError }}



{{ $ctrl.$stateParams.error.message }}
src/angular/pages/p3xr-error.js000066400000000000000000000003451520131260200167500ustar00rootroot00000000000000p3xr.ng.component('p3xrError', { template: require('./p3xr-error.html'), controller: function ($stateParams, $rootScope) { this.$stateParams = $stateParams $rootScope.p3xr.state.failed = true; } }) src/angular/pages/p3xr-main.html000066400000000000000000000113241520131260200170720ustar00rootroot00000000000000

{{ $root.p3xr.strings.intention.main }}

{{ $root.p3xr.strings.title.main }}
{{ $root.p3xr.strings.intention.noConnections }}
src/angular/pages/p3xr-main.js000066400000000000000000000446061520131260200165530ustar00rootroot00000000000000p3xr.ng.component('p3xrMain', { template: require('./p3xr-main.html'), controller: function ($cookies, p3xrSocket, p3xrCommon, p3xrRedisParser, $rootScope, $state, $timeout, $scope, $mdMedia) { let $container let $header; let $footer; let $consoleHeader let scrollers let $resizer let resizerMouseoverOn = false; let resizeClicked = false; let resizeLeft = undefined Object.defineProperty($scope, 'resizerColor', { get: () => { if (resizeClicked || resizerMouseoverOn) { return 'accent-400'; } return 'accent' }, set: (val) => { // unused } }) const resizeMinWidth = p3xr.settings.resizeMinWidth; const debounce = require('lodash/debounce') let screenSizeIsSmall = false let $timeoutResize $scope.$watch(function () { return $mdMedia('xs'); }, function (isScreenSizeIsSmall) { if (!isScreenSizeIsSmall && screenSizeIsSmall === true) { if ($timeoutResize !== undefined) { $timeout.cancel($timeoutResize) } $timeoutResize = $timeout(resize, 4 * p3xr.settings.debounce) //console.warn('aha!') } screenSizeIsSmall = isScreenSizeIsSmall; }); /* const debouncedTabs = debounce(() => { $rootScope.$broadcast('p3x-refresh-statistics-tabs') }, p3xr.settings.debounce) */ const rawResize = (options = {}) => { //console.log('p3xr-main rawResize') //console.time('p3xr-main-resize') //console.info('p3xr-main resize') /* let {redrawTabs} = options if (redrawTabs === undefined) { redrawTabs = false; } */ let minus = 0 let $components //if ($rootScope.isElectron) { // $components = [$footer, $consoleHeader] //} else { $components = [$header, $footer, $consoleHeader] //} for (let item of $components) { minus += item.outerHeight() } const windowHeight = $window.outerHeight() //console.log(windowHeight, minus) //const outputPositionMinus = $rootScope.isElectron ? 0 : 10 const outputPositionMinus = 11 const outputHeight = Math.max(windowHeight - minus - outputPositionMinus, 100) $container.height(outputHeight) $container.css('max-height', `${outputHeight}px`) const containerPosition = p3xr.dom.getPosition($container[0]) const $treeControl = $('#p3xr-main-treecontrol-container') if ($treeControl) { const $treeControlControls = $('#p3xr-main-treecontrol-controls-container') const treeControlControlsPosition = p3xr.dom.getPosition($treeControlControls[0]) $treeControl.css('top', (containerPosition.top + treeControlControlsPosition.height) + 'px') $treeControl.css('left', containerPosition.left + 'px'); $treeControl.css('height', (containerPosition.height - treeControlControlsPosition.height) + 'px') $treeControl.css('max-height', containerPosition.height + 'px') if (resizeLeft !== undefined) { $treeControl.css('width', (resizeLeft - containerPosition.left) + 'px') } else { $treeControl.css('width', resizeMinWidth + 'px') } $treeControl.css('min-width', resizeMinWidth + 'px') const treeControlPosition = p3xr.dom.getPosition($treeControl[0]) if ($resizer === undefined) { decorateResizer(); } const resizerWidth = 5; if ($resizer !== undefined) { // $resizer.removeEventListener('mouseover', resizerMouseover) // $resizer.removeEventListener('mouseout', resizeMouseout ) $resizer = document.getElementById('p3xr-main-content-sizer') if ($resizer !== null) { $resizer.addEventListener('mouseover', resizerMouseover) $resizer.addEventListener('mouseout', resizeMouseout) $resizer.style.top = containerPosition.top + 'px' $resizer.style.height = containerPosition.height + 'px' $resizer.style.left = (containerPosition.left + treeControlPosition.width) + 'px' $resizer.style.width = (resizerWidth) + 'px' } } const $content = $('#p3xr-main-content-container'); $content.css('top', containerPosition.top + 'px') $content.css('height', containerPosition.height + 'px') $content.css('left', (containerPosition.left + treeControlPosition.width + resizerWidth) + 'px') $content.css('width', (containerPosition.width - treeControlPosition.width - resizerWidth) + 'px') $treeControlControls.width(treeControlPosition.width) } else { destroyResizer() } /* if (redrawTabs) { debouncedTabs() } */ //console.timeEnd('p3xr-main-resize') }; const resize = debounce(() => { resizeLeft = undefined rawResize() }, p3xr.settings.debounce) const resizerMouseover = () => { resizerMouseoverOn = true; $scope.$digest(); } const resizeMouseout = () => { resizerMouseoverOn = false; $scope.$digest(); } const resizeClick = (event) => { if (event.type === 'mousedown' && event.target.id !== 'p3xr-main-content-sizer') { return } if (event.type === 'mousedown') { resizeClicked = true document.documentElement.style.cursor = `ew-resize` $body.addClass('p3xr-not-selectable') } else if (event.type === 'mouseup') { document.documentElement.style.cursor = `auto` resizeClicked = false $body.removeClass('p3xr-not-selectable') } if (resizeClicked === false) { rawResize({ //redrawTabs: true }); } event.stopPropagation(); $scope.$digest(); } const documentMousemove = (event) => { if (resizeClicked) { const containerPosition = p3xr.dom.getPosition($container[0]) if (event.clientX < containerPosition.left + resizeMinWidth || event.clientX > window.innerWidth - resizeMinWidth) { // console.warn('not allowed to resize with too small position') document.documentElement.style.cursor = 'not-allowed' } else { document.documentElement.style.cursor = 'ew-resize' $resizer.style.left = event.clientX + 'px' resizeLeft = event.clientX; rawResize(); } } } const decorateResizer = () => { $resizer = document.getElementById('p3xr-main-content-sizer'); if ($resizer === null) { $resizer = undefined return; } $resizer.addEventListener('mouseover', resizerMouseover) $resizer.addEventListener('mouseout', resizeMouseout) // $resizer.on('click', resizeClick) document.addEventListener("mousemove", documentMousemove); document.addEventListener("mousedown", resizeClick); document.addEventListener("mouseup", resizeClick); // document.addEventListener("click", documentClick); } $scope.$on('p3xr-main-resizer', (event, opts) => { console.info('p3xr-main-resizer dragging:', opts.drag) if (opts.drag === true) { document.addEventListener("mousemove", documentMousemove); document.addEventListener("mousedown", resizeClick); document.addEventListener("mouseup", resizeClick); } else { document.removeEventListener("mousemove", documentMousemove); document.removeEventListener("mousedown", resizeClick); document.removeEventListener("mouseup", resizeClick); } }) const destroyResizer = () => { if ($resizer !== undefined && $resizer !== null) { $resizer.removeEventListener('mouseover', resizerMouseover) $resizer.removeEventListener('mouseout', resizeMouseout) $resizer = undefined } document.removeEventListener("mousedown", resizeClick); document.removeEventListener("mouseup", resizeClick); document.removeEventListener("mousemove", documentMousemove); } this.resize = debounce(rawResize, p3xr.settings.debounce) this.resizeRaw = rawResize /* this.$doCheck = () => { console.log('do check') rawResize() } */ this.$onInit = () => { require('../../core/node-inview-recursive').recursive({ nodes: $rootScope.keysTreeRendered, }) $container = $('#p3xr-main-content') $header = $('#p3xr-layout-header-container') $footer = $('#p3xr-layout-footer-container') $consoleHeader = $('#p3xr-main-header') scrollers = $container[0] rawResize() $window.on('resize', rawResize) if ($state.current.url === '/main') { $state.go('main.statistics') } if (p3xr.state.redisChanged) { p3xr.state.redisChanged = false; //console.warn('p3xr', p3xr) if (p3xr.state.connection) { this.refresh() } } if (p3xr.state.connections.list.length === 0 && p3xr.state.connection === undefined) { setTimeout(() => { rawResize() }, 250) } } this.$onDestroy = function () { $window.off('resize', rawResize) destroyResizer(); }; $rootScope.p3xr.state.page = 1; let selectedDatabase = 0 let currentDatabase Object.defineProperty(this, 'currentDatabase', { get: () => { let currentDatabase = p3xr.state.currentDatabase if (currentDatabase === undefined) { currentDatabase = $cookies.get(p3xr.settings.connection.getCookieNameCurrentDatabase(p3xr.state.connection.id)) } if (currentDatabase === undefined) { currentDatabase = 0; } return currentDatabase; }, set: async (value) => { currentDatabase = value if (selectedDatabase !== currentDatabase) { selectedDatabase = value try { const response = await p3xrSocket.request({ action: 'console', payload: { command: `select ${selectedDatabase}` } }) } catch (e) { p3xrCommon.generalHandleError(e) } } $cookies.put(p3xr.settings.connection.getCookieNameCurrentDatabase(p3xr.state.connection.id), String(value), { expires: p3xr.settings.cookieExpiry, }) } }) this.selectDatabase = async (selectDbIndex) => { this.currentDatabase = selectDbIndex try { $rootScope.p3xr.state.page = 1; const response = await p3xrSocket.request({ action: 'console', payload: { command: `select ${selectDbIndex}` } }) p3xrCommon.toast({ message: p3xr.strings.status.dbChanged({ db: selectDbIndex }) }) await this.statistics() } catch (e) { p3xrCommon.generalHandleError(e) } } this.save = async () => { try { const response = await p3xrSocket.request({ action: 'save', }) $rootScope.p3xr.state.info = p3xrRedisParser.info(response.info) //$rootScope.p3xr.state.infoObject = response.infoObject $rootScope.$digest() p3xrCommon.toast({ message: p3xr.strings.status.savedRedis }) } catch (e) { p3xrCommon.generalHandleError(e) } } this.statistics = async () => { try { $state.go('main.statistics') await this.refresh() } catch (e) { p3xrCommon.generalHandleError(e) } } this.refresh = async (options = {}) => { console.time('refresh') let { withoutParent } = options if (withoutParent === undefined) { withoutParent = false } let expandedNodes = angular.copy($rootScope.expandedNodes); try { /* p3xr.ui.overlay.show({ message: p3xr.strings.status.reloadingDataInfo }) */ const payload = {} if (!$rootScope.p3xr.settings.searchClientSide && typeof ($rootScope.p3xr.state.search) === 'string' && $rootScope.p3xr.state.search.length > 0) { if ($rootScope.p3xr.settings.searchStartsWith) { payload.match = $rootScope.p3xr.state.search + '*'; } else { payload.match = '*' + $rootScope.p3xr.state.search + '*'; } } //console.warn('match', payload.match, 'search', $rootScope.p3xr.state.search) const response = await p3xrSocket.request({ action: 'refresh', payload: payload }) p3xr.state.dbsize = response.dbsize $rootScope.p3xr.state.redisChanged = true // if (keepTree) { // $timeout(() => { $rootScope.savedExpandedNodes = expandedNodes // p3xrCommon.loadRedisInfoResponse() // }) // } p3xrCommon.loadRedisInfoResponse({ response: response }) if (!withoutParent) { $rootScope.$broadcast('p3x-refresh-key'); } } catch (e) { p3xrCommon.generalHandleError(e) /* $timeout(() => { p3xr.ui.overlay.hide() }, p3xr.settings.debounce) */ } finally { /* p3xr.ui.overlay.hide() */ } console.timeEnd('refresh') setTimeout(() => { $rootScope.$digest() }) } $scope.$on('p3x-refresh', () => { this.refresh({ withoutParent: true }) //resize() }) let currentElement let resizeObserver = new ResizeObserver(entries => { if (!resizeClicked) { //console.log('ResizeObserver resize', JSON.parse(JSON.stringify(entries))) rawResize() } }) const watchResize = async(newVal, oldVal) => { if (currentElement) { resizeObserver.unobserve(currentElement) } if (p3xr.state.connection === undefined) { console.log('no connection for resizing') return } if ($mdMedia('xs')) { rawResize() return } let elem = null while (elem === null ) { elem = document.getElementById('p3xr-main-treecontrol-controls-container') console.info('waiting for observing tree control controls') await new Promise(resolve => setTimeout(() => { resolve() })) } console.info('found observing tree control controls') // console.log('elem', elem) currentElement = elem resizeObserver.observe(currentElement) // console.log('watching width') } $scope.$watch(() => { return ($mdMedia('xs') ? 'true' : 'false') + '-' + (p3xr.state.connection ? 'true' : 'false') }, watchResize) $scope.$on('$destroy', () => { resizeObserver.disconnect() }) this.addKey = (options) => { const {event, node} = options // event.preventDefault() event.stopPropagation(); $rootScope.$broadcast('p3xr-key-new', { event: event, node: node, }); } /* redis version = server - redis_version keys = keyspace - dbIndex -> keys memory used -> memory - used_memory_human uptime -> server - uptime_in_days last save - save = 0) { echo format_time(time() - $info[$i]['Persistence']['rdb_last_save_time']) . " ago"; } else { echo format_time(-(time() - $info[$i]['Persistence']['rdb_last_save_time'])) . "in the future"; } } else { echo 'never'; } ?> */ } }) src/angular/pages/p3xr-main.scss000066400000000000000000000014511520131260200171010ustar00rootroot00000000000000p3xr-main { @media (max-width:350px) { .p3xr-main-toolbar-button-hide-on-small { display: none; } } #p3xr-main-treecontrol-container { position: fixed; overflow: auto; } #p3xr-main-treecontrol-container-directive-small { max-height: 220px; overflow: auto; } .p3xr-main-treecontrol-folder-icon { transform: scale(0.75); } #p3xr-main-content-container { position: fixed; overflow: auto; display: block; } .p3xr-main-toolbar-button { } .p3xr-main-db-select { .md-select-value { border-bottom: none !important; } } } #p3xr-main-content-sizer { position: fixed; display: block; cursor: ew-resize; z-index: 10; } src/angular/pages/p3xr-overview.html000066400000000000000000000020441520131260200200130ustar00rootroot00000000000000 {{ $root.p3xr.strings.page.overview.overviewClients }}

{{ connectionValue.connection.name }}

{{ connectionValue.connection.host }}:{{ connectionValue.connection.port }}

{{ $root.p3xr.strings.page.overview.connectedCount({ length: connectionValue.clients.length }) }}

src/angular/pages/p3xr-overview.js000066400000000000000000000003451520131260200174650ustar00rootroot00000000000000/* p3xr.ng.component('p3xrOverview', { template: require('./p3xr-overview.html'), controller: function ($rootScope, $state) { if (!$rootScope.hasConnected()) { $state.go('main') } } }) */ src/angular/pages/p3xr-settings.html000066400000000000000000000220521520131260200200060ustar00rootroot00000000000000
{{ $root.p3xr.strings.intention.noConnectionsInSettings }}

{{connection.name}}

{{connection.host}}:{{connection.port}}

delete_forever {{ $root.p3xr.strings.intention.delete }} {{ $root.p3xr.strings.intention.delete }} edit {{ $root.p3xr.strings.intention.edit }} {{ $root.p3xr.strings.intention.edit }} mode_comment {{ $root.p3xr.strings.intention.view }} {{ $root.p3xr.strings.intention.view }}

{{ $root.p3xr.strings.form.treeSettings.field.treeSeparator}}
{{ $root.p3xr.settings.redisTreeDivider}} {{ $root.p3xr.strings.label.treeSeparatorEmptyNote}}
{{ $root.p3xr.strings.form.treeSettings.field.page}}
{{ $root.p3xr.settings.pageCount}}

{{ $root.p3xr.strings.form.treeSettings.maxValueDisplay}}
{{ $root.p3xr.settings.maxValueDisplay}}

{{ $root.p3xr.strings.form.treeSettings.maxValueDisplayInfo }}

{{ $root.p3xr.strings.form.treeSettings.maxKeys}}
{{ $root.p3xr.settings.maxKeys}}

{{ $root.p3xr.strings.form.treeSettings.maxKeysInfo }}

{{ $root.p3xr.strings.form.treeSettings.field.keysSort}}
{{ $root.p3xr.settings.keysSort ? $root.p3xr.strings.label.keysSort.on : $root.p3xr.strings.label.keysSort.off }}
{{ $root.p3xr.strings.form.treeSettings.field.searchMode}}
{{ $root.p3xr.settings.searchClientSide ? $root.p3xr.strings.form.treeSettings.label.searchModeClient : $root.p3xr.strings.form.treeSettings.label.searchModeServer }}
{{ $root.p3xr.strings.form.treeSettings.field.searchModeStartsWith}}
{{ $root.p3xr.settings.searchStartsWith ? $root.p3xr.strings.form.treeSettings.label.searchModeStartsWith : $root.p3xr.strings.form.treeSettings.label.searchModeIncludes }}
{{ $root.p3xr.settings.jsonFormat == 2 ? $root.p3xr.strings.form.treeSettings.label.jsonFormatTwoSpace : $root.p3xr.strings.form.treeSettings.label.jsonFormatFourSpace }}
{{ $root.p3xr.settings.animation ? $root.p3xr.strings.form.treeSettings.label.animation : $root.p3xr.strings.form.treeSettings.label.noAnimation }}
src/angular/pages/p3xr-settings.js000066400000000000000000000063561520131260200174670ustar00rootroot00000000000000p3xr.ng.component('p3xrSettings', { template: require('./p3xr-settings.html'), controller: function (p3xrCommon, p3xrDialogConnection, $mdDialog, p3xrSocket, p3xrDialogTreecontrolSettings) { this.connectionForm = (options) => { p3xrDialogConnection.show(options) } this.setLicense = async (options) => { try { const confirm = $mdDialog.prompt() .title(p3xr.strings.confirm.license.title) .textContent(p3xr.strings.confirm.license.textContent) .placeholder(p3xr.strings.confirm.license.placeholder) .ariaLabel(p3xr.strings.confirm.license.placeholder) .initialValue('') .targetEvent(options.$event) .ok(p3xr.strings.intention.license) .cancel(p3xr.strings.intention.cancel); const confirmResponse = await $mdDialog.show(confirm) const response = await p3xrSocket.request({ action: 'set-license', payload: { license: confirmResponse } }) if (!global.p3xr.isBot() && response.donated !== p3xr.state.donated) { window['gtag']('config', p3xr.settings.googleAnalytics, { 'page_path': response.donated ? '/donated' : '/free' } ); } p3xr.state.donated = response.donated //await this.refresh() p3xrCommon.toast({ message: response.info !== 'ok' ? p3xr.strings.error[response.info] : p3xr.strings.status.licenseSaved, }) } catch (e) { if (e === undefined) { return } if (p3xr.strings.error[e.message]) { e = new Error(p3xr.strings.error[e.message]) } p3xrCommon.generalHandleError(e) } } this.openTreeSettingDialog = (opts) => { p3xrDialogTreecontrolSettings.show(opts); //console.warn($rootScope.p3xr.state.redisTreeDivider) } this.deleteConnection = async (options) => { const {model, ev} = options; try { await p3xrCommon.confirm({ event: ev, message: p3xr.strings.confirm.deleteConnectionText }); const response = await p3xrSocket.request({ action: 'connection-delete', payload: { id: model.id }, }) p3xrCommon.toast({ message: p3xr.strings.status.deleted }); } catch (error) { if (error === undefined) { /* p3xrCommon.toast({ message: p3xr.strings.status.cancelled }); */ return; } p3xrCommon.generalHandleError(error) } } } }) src/angular/pages/p3xr-settings.scss000066400000000000000000000001221520131260200200070ustar00rootroot00000000000000@import "../../scss/vars"; .p3xr-settings-bottom { height: $toolbar-height; } src/angular/provider/000077500000000000000000000000001520131260200151205ustar00rootroot00000000000000src/angular/provider/p3xr-theme.js000066400000000000000000000163601520131260200174600ustar00rootroot00000000000000const MobileDetect = require('mobile-detect') const md = new MobileDetect(window.navigator.userAgent); const isMobile = md.mobile() !== null || md.phone() !== null || md.tablet() !== null p3xr.ng.provider('p3xrTheme', function p3xrThemeProvider($mdThemingProvider,) { const selfProvider = this; $mdThemingProvider.generateThemesOnDemand(true); $mdThemingProvider.alwaysWatchTheme(true); $mdThemingProvider.setNonce(); const themeCookieName = 'p3xr-theme' const themeDefault = 'p3xrThemeLight'; this.start = () => { // console.warn('ngivrTheme we are in the provider eg: config')( Object.keys(p3xr.theme).forEach(theme => { //console.warn('provider theme: ', theme) p3xr.theme[theme]($mdThemingProvider) }) $mdThemingProvider.setDefaultTheme(themeDefault); } const themeIsGenerated = {}; const themeType = { dark: [ 'p3xrThemeDarkNeu', 'p3xrThemeDark', 'p3xrThemeDarkoBluo', 'p3xrThemeMatrix', ], light: [ 'p3xrThemeLight', 'p3xrThemeEnterprise', 'p3xrThemeRedis', ] } // this is the service eg: ngivrTheme this.$get = ['$mdTheming', '$rootScope', '$cookies', '$mdColors', function p3xThemeFactory($mdTheming, $rootScope, $cookies, $mdColors) { // let's assume that the UnicornLauncher constructor was also changed to // accept and use the useTinfoilShielding argument return new function p3xrTheme() { const self = this; this.isDark = () => { return themeType.dark.includes(this.getCurrentThemeName()) } this.start = () => { // console.log(selfProvider); // console.log('ngivrTheme we are in the service eg: run or injector') self.setTheme(); } this.setTheme = (themeName) => { if (themeName === undefined) { themeName = $cookies.get(themeCookieName) if (themeName === undefined) { themeName = themeDefault } } //console.warn(`theme will generate theme on the fly: ${theme}`); if (!themeIsGenerated.hasOwnProperty(themeName)) { //console.warn(`theme generating theme on the fly: ${theme}`); $mdTheming.generateTheme(themeName); $mdTheming.generateTheme(`${themeName}Layout`); $mdTheming.generateTheme(`${themeName}Common`); themeIsGenerated[themeName] = true; } //console.warn(themeIsGenerated) //console.warn(`theme registered: ${$mdTheming.registered(theme)}`); $mdThemingProvider.setDefaultTheme(themeName); $rootScope.p3xr.state.theme = themeName; $cookies.put(themeCookieName, themeName, {expires: p3xr.settings.cookieExpiry,}); $body.removeClass('p3xr-theme-light') $body.removeClass('p3xr-theme-dark') if (themeType.dark.includes(themeName)) { $body.addClass('p3xr-theme-dark') } else { $body.addClass('p3xr-theme-light') } $('#p3xr-theme-styles').remove() const darkColor = p3xr.state.themeCommon + '-background'; //console.warn(darkColor) const borderColor = $mdColors.getThemeColor(p3xr.state.themeLayout + '-primary-hue-1'); const styles = ` .p3xr-theme-dark .p3xr-content-border { border-left: 1px solid ${borderColor}; border-right: 1px solid ${borderColor}; border-bottom: 1px solid ${borderColor}; } .p3xr-theme-light .p3xr-content-border { border-left: 1px solid transparent; border-right: 1px solid transparent; border-bottom: 1px solid transparent; } .p3xr-toast-default .md-toast-content { background-color: ${this.isDark() ? $mdColors.getThemeColor(darkColor) : 'auto'} !important; border: solid 1px ${this.isDark() ? 'rgba(255, 255, 255, 0.5)' : 'auto'} !important; ${this.isDark() ? 'box-shadow: 0 0 10px rgba(0,0,0,0.6);' : ''} } treecontrol i.tree-branch-head:before { color: ${this.isDark() ? $mdColors.getThemeColor('amber-A100') : $mdColors.getThemeColor('amber-A400')}; ${this.isDark() ? 'text-shadow: 1px 1px 1px rgba(55, 29, 27, 0.5);' : 'text-shadow: 1px 1px 0px rgba(55, 11, 0, 0.5);' } } body.p3xr-theme-dark[md-theme="p3xrThemeMatrixLayout"] treecontrol i.tree-branch-head:before { color: ${$mdColors.getThemeColor('lime-A400')} !important; } .p3xr-list-key-odd-item { background-color: ${$mdColors.getThemeColor(p3xr.state.themeLayout + '-background-500-0.1')}; } .p3xr-list-key-item { border-bottom: 1px solid ${this.isDark() ? $mdColors.getThemeColor(p3xr.state.themeLayout + '-background-300-0.1') : $mdColors.getThemeColor(p3xr.state.themeLayout + '-background-700-0.1') }; } input:-webkit-autofill, input:-webkit-autofill:focus { -webkit-box-shadow:0 0 0 50px ${this.isDark() ? 'rgb(66, 66, 66, 0.9)' : 'rgba(255, 255, 255, 0.5)'} inset !important; -webkit-text-fill-color: ${this.isDark() ? 'white' : 'black'} !important; } ` $('head').append('') const ngivrCoreThemeMetaName = 'p3xr-theme-meta' const ngivrCoreThemeMetaElement = document.getElementById(ngivrCoreThemeMetaName) if (ngivrCoreThemeMetaElement) { ngivrCoreThemeMetaElement.remove() } const meta = document.createElement('meta'); meta.id = ngivrCoreThemeMetaName // meta.name = 'theme-color' meta.content = $mdColors.getThemeColor(p3xr.state.themeLayout + '-accent') document.head.appendChild(meta) // https://stackoverflow.com/questions/65940522/how-do-i-switch-to-chromes-dark-scrollbar-like-github-does // but fixed by p3x-robot document.documentElement.style.display = 'none'; document.documentElement.setAttribute( "data-color-scheme", this.isDark() ? "dark" : "light" ); // remove scrollbars // document.documentElement.style.overflow = "hidden"; // trigger reflow so that overflow style is applied document.body.clientWidth; // remove overflow style, which will bring back the scrollbar with the correct scheme // document.documentElement.style.overflow = ""; document.documentElement.style.display = ''; $rootScope.$broadcast('p3xr-theme-switched') } this.getCurrentThemeName = () => { return $cookies.get(themeCookieName); } this.generateThemeName = (themeNameRaw) => { const generateThemeName = 'p3xrTheme' + themeNameRaw[0].toUpperCase() + themeNameRaw.substring(1) return generateThemeName; } }; }]; }); src/angular/provider/p3xr-theme.scss000066400000000000000000000032611520131260200200130ustar00rootroot00000000000000[data-color-scheme="dark"] { color-scheme: dark; } [data-color-scheme="light"] { color-scheme: light; } .p3xr-theme-light { md-checkbox.md-checked .md-icon { background-color: rgba(0, 0, 0, 0.5); } } md-checkbox:not(.md-checked) .md-icon { border-color: rgb(0, 0, 0) !important; } .p3xr-theme-dark { md-checkbox.md-checked .md-icon { background-color: rgba(255, 255, 255, 0.5); } md-select-menu md-content md-option[selected], md-select-menu md-content md-option[selected].md-focused, md-select-menu md-content md-option[selected]:focus { color: white; } #p3xr-main-header .md-select-icon { color: black !important; } } body.p3xr-theme-dark[md-theme="p3xrThemeDarkoBluoLayout"] { #p3xr-main-header .md-select-icon { color: white !important; } md-checkbox:not(.md-checked) .md-icon { border-color: rgb(255, 255, 255) !important; } } body.p3xr-theme-light[md-theme="p3xrThemeRedisLayout"] { md-checkbox.md-checked .md-icon { background-color: rgba(255, 255, 255, 0.5); } .p3xr-main-db-select-container { md-select-menu md-content md-option[selected], md-select-menu md-content md-option[selected].md-focused, md-select-menu md-content md-option[selected]:focus { color: white; } } #p3xr-main-header .md-select-icon { color: black !important; } } body.p3xr-theme-dark[md-theme="p3xrThemeMatrixLayout"] { md-checkbox.md-checked .md-icon { background-color: transparent; border-color: black; } } md-select:not([disabled]):focus .md-select-value { color: inherit !important; } src/angular/provider/theme-generator/000077500000000000000000000000001520131260200202065ustar00rootroot00000000000000src/angular/provider/theme-generator/p3xr-theme-dark-neu.js000066400000000000000000000017471520131260200242550ustar00rootroot00000000000000p3xr.theme.darkNeu = function ($mdThemingProvider, p3xrThemeNameGenerator) { p3xr.theme.darkNeu.order = 1 $mdThemingProvider.theme('p3xrThemeDarkNeuLayout') .primaryPalette('blue-grey', { 'default': '800', 'hue-1': '300', 'hue-2': '700', 'hue-3': '900', }) .accentPalette('blue-grey', { 'default': '300', }) .warnPalette('grey') .backgroundPalette('grey', { default: '900', }) .dark() ; $mdThemingProvider.theme(`p3xrThemeDarkNeu`) .primaryPalette('cyan') .accentPalette('blue') .warnPalette('yellow') // .backgroundPalette('blue-grey') .dark() ; $mdThemingProvider.theme(`p3xrThemeDarkNeuCommon`) .primaryPalette('green') .accentPalette('grey') .warnPalette('blue') .backgroundPalette('blue-grey', { default: '900' }) .dark() ; } src/angular/provider/theme-generator/p3xr-theme-dark.js000066400000000000000000000021771520131260200234660ustar00rootroot00000000000000p3xr.theme.dark = function ($mdThemingProvider) { p3xr.theme.dark.order = 3 $mdThemingProvider.theme(`p3xrThemeDarkLayout`) .primaryPalette('grey', { 'default': '800', 'hue-1': '500', 'hue-2': '700', 'hue-3': '900', }) .accentPalette('grey') .warnPalette('grey') .backgroundPalette('grey', { 'default': '900', 'hue-1': '800', 'hue-2': '700', 'hue-3': '900', }) ; $mdThemingProvider.theme(`p3xrThemeDarkLayout`).dark() $mdThemingProvider.theme(`p3xrThemeDark`) .primaryPalette('indigo', { default: '300' }) .accentPalette('blue') .warnPalette('orange') .backgroundPalette('grey') ; $mdThemingProvider.theme(`p3xrThemeDark`).dark() $mdThemingProvider.theme(`p3xrThemeDarkCommon`) .primaryPalette('green') .accentPalette('grey') .warnPalette('indigo', { default: '200', }) .backgroundPalette('grey') ; $mdThemingProvider.theme(`p3xrThemeDarkCommon`).dark() } src/angular/provider/theme-generator/p3xr-theme-darko-bluo.js000066400000000000000000000026051520131260200246000ustar00rootroot00000000000000p3xr.theme.darkoBluo = function ($mdThemingProvider) { p3xr.theme.darkoBluo.order = 5 $mdThemingProvider.theme(`p3xrThemeDarkoBluoLayout`) .primaryPalette('indigo', { 'default': '900', 'hue-1': '500', 'hue-2': '700', 'hue-3': '900', }) .accentPalette('indigo', { 'default': '600', 'hue-1': '50', 'hue-2': '700', 'hue-3': '900', }) .warnPalette('indigo') .backgroundPalette('grey', { 'default': '900', 'hue-1': '900', 'hue-2': '500', 'hue-3': '100', }) ; $mdThemingProvider.theme(`p3xrThemeDarkoBluoLayout`).dark() $mdThemingProvider.theme(`p3xrThemeDarkoBluo`) .primaryPalette('indigo', { 'default': '300', 'hue-1': '50', 'hue-2': '700', 'hue-3': '900', }) .accentPalette('blue') .warnPalette('orange') .backgroundPalette('grey') ; $mdThemingProvider.theme(`p3xrThemeDarkoBluo`).dark() $mdThemingProvider.theme(`p3xrThemeDarkoBluoCommon`) .primaryPalette('green') .accentPalette('grey') .warnPalette('light-blue') .backgroundPalette('indigo', { default: '700' }) ; $mdThemingProvider.theme(`p3xrThemeDarkoBluoCommon`).dark() } src/angular/provider/theme-generator/p3xr-theme-enterprise.js000066400000000000000000000020651520131260200247210ustar00rootroot00000000000000p3xr.theme.enterprise = function ($mdThemingProvider, p3xrThemeNameGenerator) { p3xr.theme.enterprise.order = 2 $mdThemingProvider.theme('p3xrThemeEnterpriseLayout') .primaryPalette('grey', { 'default': '800', 'hue-1': '500', 'hue-2': '700', 'hue-3': '900', }) .accentPalette('grey', { 'default': '600', 'hue-1': '50', 'hue-2': '700', 'hue-3': '900', }) .warnPalette('grey') .backgroundPalette('grey', { default: '400' }) ; $mdThemingProvider.theme(`p3xrThemeEnterprise`) .primaryPalette('indigo') .accentPalette('blue', { default: '700', }) .warnPalette('red', { default: '700', }) // .backgroundPalette('grey') ; $mdThemingProvider.theme(`p3xrThemeEnterpriseCommon`) .primaryPalette('green') .accentPalette('grey') .warnPalette('light-blue') // .backgroundPalette('grey') ; } src/angular/provider/theme-generator/p3xr-theme-light.js000066400000000000000000000020401520131260200236410ustar00rootroot00000000000000p3xr.theme.light = function ($mdThemingProvider, p3xrThemeNameGenerator) { p3xr.theme.light.order = 0; $mdThemingProvider.theme('p3xrThemeLightLayout') .primaryPalette('blue-grey', { 'default': '800', 'hue-1': '200', 'hue-2': '700', 'hue-3': '900', }) .accentPalette('blue-grey') .warnPalette('grey') .backgroundPalette('blue-grey', { 'default': 'A100', 'hue-1': '50', 'hue-2': '700', 'hue-3': '900', }) ; $mdThemingProvider.theme(`p3xrThemeLight`) .primaryPalette('deep-purple') .accentPalette('purple', { default: '500' }) .warnPalette('red', { default: '700' }) .backgroundPalette('blue-grey') ; $mdThemingProvider.theme(`p3xrThemeLightCommon`) .primaryPalette('green') .accentPalette('grey') .warnPalette('blue-grey') .backgroundPalette('blue-grey') ; return this } src/angular/provider/theme-generator/p3xr-theme-matrix.js000066400000000000000000000031361520131260200240450ustar00rootroot00000000000000p3xr.theme.matrix = function ($mdThemingProvider) { p3xr.theme.matrix.order = 5 $mdThemingProvider.theme(`p3xrThemeMatrixLayout`) .primaryPalette('light-green', { 'default': 'A400', 'hue-1': 'A400', 'hue-2': '700', 'hue-3': '900', }) .accentPalette('light-green', { 'default': 'A400', 'hue-1': '100', 'hue-2': '600', 'hue-3': '800', }) .warnPalette('green') .backgroundPalette('grey', { 'default': '900', 'hue-1': '900', 'hue-2': '500', 'hue-3': '100', }) .dark() ; $mdThemingProvider.theme(`p3xrThemeMatrix`) .primaryPalette('light-green', { 'default': 'A400', 'hue-1': '50', 'hue-2': '700', 'hue-3': '900', }) .accentPalette('lime', { 'default': 'A400', }) .warnPalette('green', { 'default': 'A700', }) .backgroundPalette('grey') .dark() ; $mdThemingProvider.theme(`p3xrThemeMatrixCommon`) .primaryPalette('light-green', { default: 'A400', 'hue-1': 'A400', 'hue-2': 'A400', 'hue-3': 'A400', }) .accentPalette('light-green', { default: 'A400', 'hue-1': 'A400', 'hue-2': 'A400', 'hue-3': 'A400', }) .warnPalette('green') .backgroundPalette('grey', { default: '900' }) .dark() ; } src/angular/provider/theme-generator/p3xr-theme-redis.js000066400000000000000000000020231520131260200236410ustar00rootroot00000000000000p3xr.theme.redis = function ($mdThemingProvider, p3xrThemeNameGenerator) { p3xr.theme.redis.order = 4 $mdThemingProvider.theme('p3xrThemeRedisLayout') .primaryPalette('red', { 'default': '800', 'hue-1': '200', 'hue-2': '700', 'hue-3': '900', }) .accentPalette('red', { default: '200' }) .warnPalette('red') .backgroundPalette('red', { 'default': '900', 'hue-1': '600', 'hue-2': '200', 'hue-3': '200', }) ; $mdThemingProvider.theme(`p3xrThemeRedis`) .primaryPalette('grey', { default: '900' }) .accentPalette('grey', { default: '600' }) .warnPalette('amber') // .backgroundPalette('blue-grey') ; $mdThemingProvider.theme(`p3xrThemeRedisCommon`) .primaryPalette('green') .accentPalette('grey') .warnPalette('red') .backgroundPalette('grey') ; } src/angular/routes.js000066400000000000000000000023641520131260200151520ustar00rootroot00000000000000const routes = ($stateProvider, $urlRouterProvider) => { $stateProvider.state({ name: 'settings', url: '/settings', template: '' }) $stateProvider.state({ name: 'main', url: '/main', template: '' }) /* $stateProvider.state({ name: 'overview', url: '/overview', template: '' }) */ $stateProvider.state({ name: 'console', url: '/console', template: '' }) $stateProvider.state('main.statistics', { url: '/statistics', template: '', params: { action: null, expandedNodes: null, response: null, }, }); $stateProvider.state('main.key', { url: '/key/:key', template: '', params: { resize: null, } }); $stateProvider.state('socketio-error', { url: '/socketio-error', template: '', params: { error: null } }); } module.exports = routes src/angular/ui/000077500000000000000000000000001520131260200137035ustar00rootroot00000000000000src/angular/ui/p3xr-accordion.html000066400000000000000000000020571520131260200174300ustar00rootroot00000000000000

{{ $ctrl.p3xrTitle }}

{{ !$ctrl.extended ? 'keyboard_arrow_down' : 'keyboard_arrow_up' }} {{ !$ctrl.extended ? $root.p3xr.strings.intention.extend : $root.p3xr.strings.intention.collapse}}
src/angular/ui/p3xr-accordion.js000066400000000000000000000024351520131260200171000ustar00rootroot00000000000000let accordionKey = 0 p3xr.ng.component('p3xrAccordion', { template: require('./p3xr-accordion.html'), bindings: { p3xrTitle: '<', p3xrAccordionKey: '@', }, transclude: { 'actions': '?p3xrAccordionActions', 'content': 'p3xrAccordionContent', }, controller: function ($transclude, $cookies) { this.transcludePresent = function (slot) { return $transclude.isSlotFilled(slot); }; this.$onInit = function () { //console.log(this.p3xrAccordionKey) if (this.p3xrAccordionKey === undefined || this.p3xrAccordionKey === '') { this.p3xAccordionKey = ++accordionKey; } const cookieName = `p3xr-accordion-extended-${this.p3xrAccordionKey}` //console.log(cookieName) Object.defineProperty(this, 'extended', { get: () => { const cookieValue = $cookies.get(cookieName) return cookieValue === undefined ? true : cookieValue === 'true' }, set: (value) => { $cookies.put(cookieName, String(value), { expires: p3xr.settings.cookieExpiry, }) } }) } } }) src/angular/ui/p3xr-accordion.scss000066400000000000000000000002421520131260200174310ustar00rootroot00000000000000@import "../../scss/vars"; .p3xr-accordion-electron { margin-left: $layout-padding; margin-right: $layout-padding; margin-bottom: $layout-padding; } src/angular/ui/p3xr-button.html000066400000000000000000000007351520131260200170030ustar00rootroot00000000000000 {{ $ctrl.p3xrMdIcon }} {{ $ctrl.p3xrLabel }} {{ $ctrl.p3xrLabel }} src/angular/ui/p3xr-button.js000066400000000000000000000003601520131260200164450ustar00rootroot00000000000000p3xr.ng.component('p3xrButton', { template: require('./p3xr-button.html'), bindings: { p3xrLabel: '<', p3xrMdIcon: '@', p3xrFaIcon: '@', p3xrTooltipDirection: '@', p3xrClasses: '@' }, }) src/angular/ui/p3xr-input.js000066400000000000000000000010201520131260200162630ustar00rootroot00000000000000p3xr.ng.directive('p3xrInput', function (p3xrTheme, p3xrCommon) { return { template: ``, replace: true, link: function (scope) { scope.focused = false scope.p3xrCommon = p3xrCommon } } }) src/angular/ui/p3xr-input.scss000066400000000000000000000002661520131260200166350ustar00rootroot00000000000000.p3xr-input { padding: 3px; border-style: solid; border-width: 2px; margin: 1px; } .p3xr-input:focus { margin: 0px; border-width: 3px; outline: none; } src/angular/ui/p3xr-key-pager.html000066400000000000000000000025501520131260200173510ustar00rootroot00000000000000
{{ $root.p3xr.strings.page.treeControls.pager.first}} skip_previous {{ $root.p3xr.strings.page.treeControls.pager.prev}} keyboard_arrow_left / {{ $ctrl.p3xrController.pages }} {{ $root.p3xr.strings.page.treeControls.pager.next}} keyboard_arrow_right {{ $root.p3xr.strings.page.treeControls.pager.last}} skip_next
src/angular/ui/p3xr-key-pager.js000066400000000000000000000003051520131260200170150ustar00rootroot00000000000000p3xr.ng.component('p3xrKeyPager', { template: require('./p3xr-key-pager.html'), bindings: { p3xrController: '<', }, controller: function ($transclude, $cookies) { } }) src/builder/000077500000000000000000000000001520131260200132635ustar00rootroot00000000000000src/builder/webpack.config.js000066400000000000000000000154571520131260200165150ustar00rootroot00000000000000const config = require('corifeus-builder/src/utils/config').config const webpack = require('webpack'); const {CleanWebpackPlugin} = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin') const CopyWebpackPlugin = require('copy-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const minimize = process.argv.includes('--mode=production'); const mode = minimize ? 'production' : 'development'; const useStats = process.env.hasOwnProperty('WEBPACK_STATS') const filenamePrefix = minimize ? '[id].[contenthash]' : '[name]' let minimizer = undefined; const top = process.cwd() const buildDir = top + `/dist`; let devtool; const pkg = require('../../package') // https://github.com/webpack-contrib/webpack-hot-middleware/tree/master/example /* https://stackoverflow.com/questions/44317394/webpack-dev-server-with-hot-reload-reloading-entire-page-with-css-changes 'webpack-dev-server/client?http://localhost:8080', 'webpack/hot/only-dev-server', */ const vendorEntry = [ top + "/src/vendor.js" ] const mainEntry = [ top + (minimize ? "/src/main.js" : '/src/main-development.js') ] const entry = { vendor: vendorEntry, main: mainEntry, // editor: editorEntry, } if (!minimize) { vendorEntry.push('webpack/hot/only-dev-server') vendorEntry.unshift('webpack-dev-server/client?http://localhost:8080/') } const plugins = [ new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ }), new HtmlWebpackPlugin({ template: `${top}/src/index.html`, inject: 'head', scriptLoading: 'defer', chunks: ['vendor', 'main'], title: pkg.description, minify: minimize }), new MiniCssExtractPlugin({ // Options similar to the same options in webpackOptions.output // both options are optional filename: !minimize ? '[name].css' : '[id].[contenthash].css', chunkFilename: !minimize ? '[name].css' : '[id].[contenthash].css', }), ]; if (useStats) { const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; plugins.push( new BundleAnalyzerPlugin() ) } if (minimize) { plugins.unshift( new CleanWebpackPlugin() ) devtool = false; const bannerText = require('corifeus-builder').utils.license(); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); minimizer = [ new CssMinimizerPlugin(), new TerserPlugin({ parallel: true, extractComments: { condition: /^\**!|@preserve|@license|@cc_on/, filename: function (fileOptions) { return `${fileOptions.filename}.LICENSE.txt`; }, banner: function (webpackBanner) { return ` ${bannerText} For more information about all licenses, please see ${webpackBanner} `; } }, terserOptions: { compress: { warnings: false }, ecma: config.ecma, // todo found out if mangle use or not // mangle: false === keep function names // mangle: true === drop function names // for mangle true we are using angularjs-annotate with babel mangle: true, }, }), ] plugins.push( new webpack.BannerPlugin({ banner: bannerText, include: /\.css$/, exclude: /\.ts$|\.js$/, // hash:[hash], chunkhash:[chunkhash], name:[name], filebase:[filebase], query:[query], file:[file] }) ) /* https://webpack.js.org/guides/build-performance/#source-maps plugins.push( new webpack.SourceMapDevToolPlugin({ filename: 'sourcemaps/[file].map', append: '\n//# sourceMappingURL=./[url]' }) ) */ } else { plugins.push( new webpack.HotModuleReplacementPlugin() ) } const rules = [ { test: /\.js$/, enforce: 'pre', use: ['source-map-loader'], }, { test: /\.(scss|css)$/, // exclude: [`${cwd}/src/assets/ngivr.scss`], use: [ { loader: MiniCssExtractPlugin.loader, options: { }, }, 'css-loader', 'sass-loader', ], }, { test: /\.html$/i, use: [{ loader: 'html-loader', options: { minimize: minimize, esModule: false, }, }] }, { test: /\.(png|jpe?g|gif|ico)$/, type: 'asset/resource', }, { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, type: 'asset/resource', }, { test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, type: 'asset/resource', }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, type: 'asset/resource', }, { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, type: 'asset/resource', }, { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, type: 'asset/resource', }, ] let optimization = { minimize: minimize, minimizer: minimizer, /* */ } if (minimize) { rules.push({ test: /\.js$/, loader: 'webpack-remove-debug' }) rules.push( { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader?cacheDirectory" } }) } else { optimization = Object.assign(optimization, { runtimeChunk: 'single', splitChunks: { cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendor-modules', chunks: 'all', }, }, }, }) } const webpackConfig = { // watch: true, devtool: devtool, entry: entry, output: { path: buildDir, filename: `${filenamePrefix}.js`, // chunkFilename: `${filenamePrefix}.js`, // publicPath: '{{ app.url_subdir }}/webpack/', publicPath: ``, assetModuleFilename: 'assets/[hash][ext]', }, module: { rules: rules }, optimization: optimization, plugins: plugins, mode: mode, devServer: { static: { directory: './src/public', staticOptions: {}, publicPath: "/", serveIndex: true, watch: true, }, host: '0.0.0.0', historyApiFallback: { rewrites: [ {from: /.*\..*/, to: '/index.html'} ] }, hot: true, // hotOnly: true, }, } webpackConfig.ignoreWarnings = [/Failed to parse source map/]; module.exports = webpackConfig src/core/000077500000000000000000000000001520131260200125655ustar00rootroot00000000000000src/core/api.js000066400000000000000000000004341520131260200136750ustar00rootroot00000000000000global.p3xr.api = { host: undefined, } const apiUrl = new URL(location.toString()) if (global.p3xrDevMode === true && apiUrl.port === "8080") { global.p3xr.api.host = `http://${apiUrl.hostname}:7843` } else { global.p3xr.api.host = `${apiUrl.protocol}//${apiUrl.host}` } src/core/clipboard.js000066400000000000000000000004611520131260200150630ustar00rootroot00000000000000global.p3xr.clipboard = (opts) => { var copy = $(''); $('body').append(copy); copy.select(); var successful = false; try { successful = document.execCommand('copy'); } catch (err) { } copy.remove(); return successful; } src/core/dom.js000066400000000000000000000046121520131260200137050ustar00rootroot00000000000000// https://www.google.hu/search?q=javascript+vanilla+position&oq=javascript+vanilla+position&aqs=chrome..69i57.3908j0j7&sourceid=chrome&ie=UTF-8 // https://www.kirupa.com/html5/get_element_position_using_javascript.htm const dom = {} dom.getPosition = function getPosition(el) { let leftPos = 0; let topPos = 0; if (el === undefined) { return { left: 0, top: 0, width: 0, height: 0, } } const style = el.currentStyle || window.getComputedStyle(el); const width = el.offsetWidth // or use style.width const marginSide = parseFloat(style.marginLeft) + parseFloat(style.marginRight) const paddingSide = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) const borderSide = parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth) const height = el.offsetHeight // or use style.width const marginHorizontal = parseFloat(style.marginTop) + parseFloat(style.marginBottom) const paddingHorizontal = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom) const borderHorizontal = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth) const result = { width: width + marginSide + paddingSide + borderSide, height: height + marginHorizontal + paddingHorizontal + borderHorizontal } while (el) { if (el.tagName === "BODY") { // deal with browser quirks with body/window/document and page scroll const leftScroll = el.scrollLeft || document.documentElement.scrollLeft; const topScroll = el.scrollTop || document.documentElement.scrollTop; leftPos += (el.offsetLeft - leftScroll + el.clientLeft); topPos += (el.offsetTop - topScroll + el.clientTop); } else { // for all other non-BODY elements leftPos += (el.offsetLeft - el.scrollLeft + el.clientLeft); topPos += (el.offsetTop - el.scrollTop + el.clientTop); } el = el.offsetParent; } result.left = leftPos result.top = topPos return result; } /* // deal with the page getting resized or scrolled window.addEventListener("scroll", updatePosition, false); window.addEventListener("resize", updatePosition, false); function updatePosition() { // add your code to update the position when your browser // is resized or scrolled } */ p3xr.dom = domsrc/core/is-bot.js000066400000000000000000000015151520131260200143220ustar00rootroot00000000000000const pattern = new RegExp('spider|bot|yahoo|bing|google|yandex|lynx|curl|embedly|quora|outbrain|pinterest|vkShare|W3C_Validator|crawl|borg|slurp|archiver|netresearch|lycos|scooter|altavista|teoma|oegp|charlotte|http client|htdig|ichiro|mogimogi|larbin|pompos|scrubby|searchsight|semanticdiscovery|snappy|speedy|voila|vortex|voyager|zao|zeal|dataparksearch|findlinks|browsermob|httpmonitor|bingpreview|pagepeeker|webthumb|url2png|zooshot|gomeza|google sketchup|read later|pingdom|facebook|rackspace|scan|link|ezine|preview|dig|tarantula|urllib|jakarta|wget|rget|monitor|libwww|moozilla|seer|spice|snoopy|feedfetcher|wordpress|java|netfront|archive|xenu|feed|appmanager|covario|perl|host|lwp|page speed|ptst|digext|nutch|sleuth|yottaamonitor|bubing|corifeus', 'i'); global.p3xr.isBot = () => { return pattern.test(navigator.userAgent); }; src/core/next-id.js000066400000000000000000000010611520131260200144710ustar00rootroot00000000000000let currentId = 0 let currentIdTime = Date.now() global.p3xr.nextId = () => { const now = Date.now(); if (currentIdTime !== now) { currentId = 0; currentIdTime = now } const comingId = ++currentId; const randomHex = global.p3xr.random().reverse().padStart(15, '0'); const timeHex = currentIdTime.toString(16).padStart(12, '0').reverse() const comingIdHex = comingId.toString(16).padStart(3, '0').reverse(); const newId = `P3Xid${timeHex}${comingIdHex}${randomHex}`; //console.log(newId) return newId } src/core/node-inview-recursive.js000066400000000000000000000017001520131260200173520ustar00rootroot00000000000000const recursive = (opts) => { const { node, status, nodeCallback } = opts node.$inview = status if (nodeCallback) { nodeCallback({ node: node, }) } for (let child of opts.node.children) { child.$inview = status if (nodeCallback) { nodeCallback({ node: child, }) } if (child.children.length > 0) { recursive({ node: child, status: opts.status, nodeCallback: nodeCallback, }) } } } module.exports.recursive = (opts) => { let { status, nodes, nodeCallback } = opts if (status === undefined) { status = false } if (!Array.isArray(nodes)) { nodes = [ nodes ] } for (let node of nodes) { recursive({ node: node, status: status, nodeCallback: nodeCallback, }) } } src/core/random.js000066400000000000000000000002211520131260200143760ustar00rootroot00000000000000global.p3xr.random = () => { return (Math.floor(Math.random() * (99999999999999999 - 10000000000000000)) + 10000000000000000).toString(16) } src/core/settings.js000066400000000000000000000042761520131260200147740ustar00rootroot00000000000000const cookieExpiry = new Date() cookieExpiry.setFullYear(cookieExpiry.getFullYear() + 5) p3xr.settings = { maxLightKeysCount: 110000, // maxLightKeysCount: 1, resizeMinWidth: 350, socket: { timeout: 300000, }, toast: { timeout: 5000, position: 'bottom right', }, debounce: 250, debounceSearch: 2000, cookieExpiry: cookieExpiry, connection: { cookieNameCurrentDatabase: 'p3xr-main-current-database', getCookieNameCurrentDatabase: (id) => { return p3xr.settings.connection.cookieNameCurrentDatabase + '-' + id } }, tree: { cookieName: 'p3xr-main-treecontrol-divider', defaultDivider: ':', }, redisTreeDivider: ':', animation: 0, animationSettings: { default: 0, cookieName: 'p3xr-animation-settings', }, jsonFormat: 4, googleAnalytics: 'UA-169625044-1', jsonFormatSettings: { default: 4, cookieName: 'p3xr-json-format', }, paging: { default: 250, cookieName: 'p3xr-main-treecontrol-page-size' }, keyPage: { default: 5, cookieName: 'p3xr-main-key-page-size', }, keyPageCount: 5, language: { momentDateMap: { en: 'en', zn: 'zh-cn' }, defaultLanguage: 'en', current: undefined, cookieName: 'p3xr-language', translation: {} }, pageCount: 50, maxValueDisplay: 1024, maxValueDisplaySetting: { default: 1024, cookieName: 'p3xr-main-treecontrol-max-value-display' }, maxKeys: 1000, maxKeysSettings: { default: 1000, max: 100000, cookieName: 'p3xr-max-keys' }, keySortInfo: { default: true, cookieName: 'p3xr-main-treecontrol-key-sort', }, keysSort: true, searchClientSide: false, searchInfoClientSide: { default: false, cookieName: 'p3xr-main-treecontrol-search-client-mode' }, searchStartsWith: false, searchInfoStartsWith: { default: false, cookieName: 'p3xr-main-treecontrol-search-starts-with' }, connectInfo: { cookieName: 'p3xr-layout-connect', } } src/core/sort.js000066400000000000000000000014311520131260200141110ustar00rootroot00000000000000p3xr.sort = { naturalCompareDocument: () => { return (a, b) => { const regexTemplate = /(\d+)|(\D+)/g; const ax = [], bx = []; a.replace(regexTemplate, function (_, $1, $2) { ax.push([$1 || Infinity, $2 || ""]) }); b.replace(regexTemplate, function (_, $1, $2) { bx.push([$1 || Infinity, $2 || ""]) }); while (ax.length && bx.length) { const an = ax.shift(); const bn = bx.shift(); const nn = (parseFloat(an[0]) - parseFloat(bn[0])) || an[1].localeCompare(bn[1]); if (nn) { return nn; } } return ax.length - bx.length; } } } src/core/state.js000066400000000000000000000015201520131260200142410ustar00rootroot00000000000000p3xr.state = { treeDividers: [], donated: false, theme: undefined, connection: undefined, currentDatabase: undefined, redisChanged: false, databaseIndexes: [0], connections: [], redisConnections: {}, keys: [], cfg: undefined, version: undefined, keysInfo: undefined, failed: false, keysRaw: [], search: '', commands: [], reducedFunctions: false, dbsize: undefined, monitor: false, //infoObject: undefined, } Object.defineProperty(p3xr.state, 'themeLayout', { get: () => { return p3xr.state.theme + 'Layout' } }) Object.defineProperty(p3xr.state, 'themeCommon', { get: () => { return p3xr.state.theme + 'Common' } }) p3xr.connectionsReset = () => { p3xr.state.connections = { list: [] } } p3xr.connectionsReset() src/core/strings.js000066400000000000000000000001451520131260200146140ustar00rootroot00000000000000p3xr.translations = { en: require('../strings/en/strings') } p3xr.strings = p3xr.translations.en src/decorate/000077500000000000000000000000001520131260200134235ustar00rootroot00000000000000src/decorate/string.js000066400000000000000000000002071520131260200152660ustar00rootroot00000000000000if (!String.prototype.reverse) { String.prototype.reverse = function () { return this.split('').reverse().join('') } } src/editor.js000066400000000000000000000015061520131260200134630ustar00rootroot00000000000000//global.ace = require('ace-builds') //require('ace-builds/webpack-resolver') //ace.config.setModuleUrl('ace/mode/json_worker', require('file-loader?esModule=false!../node_modules/ace-builds/src-noconflict/worker-json.js')) //require('ace-builds/src-noconflict/mode-json') //require('ace-builds/src-noconflict/ext-searchbox') //require('ace-builds/src-noconflict/theme-twilight') //require('ace-builds/src-noconflict/theme-github') require('jsoneditor/dist/jsoneditor.css') global.JSONEditor = require('jsoneditor/dist/jsoneditor.js') ace.config.setModuleUrl('ace/theme/twilight', require('ace-builds/src-noconflict/theme-twilight.js')) //ace.config.setModuleUrl('ace/ext/prompt', require('ace-builds/src-noconflict/ext-prompt.js')) //ace.config.setModuleUrl('ace/theme/github', require('ace-builds/src-noconflict/theme-tomorrow.js')) src/index.html000066400000000000000000000047221520131260200136370ustar00rootroot00000000000000 P3X Redis UI
src/injector.scss000066400000000000000000000016511520131260200143520ustar00rootroot00000000000000//injector-sass-start @import "./angular/dialog/p3xr-dialog-connection.scss"; @import "./angular/dialog/p3xr-dialog-json-editor.scss"; @import "./angular/dialog/p3xr-dialog-json-view.scss"; @import "./angular/layout/p3xr-layout.scss"; @import "./angular/pages/main/key/p3xr-main-key-list.scss"; @import "./angular/pages/main/key/p3xr-main-key-string.scss"; @import "./angular/pages/main/p3xr-main-key.scss"; @import "./angular/pages/main/p3xr-main-statistics.scss"; @import "./angular/pages/main/p3xr-main-treecontrol-controls.scss"; @import "./angular/pages/main/p3xr-main-treecontrol.scss"; @import "./angular/pages/p3xr-console.scss"; @import "./angular/pages/p3xr-main.scss"; @import "./angular/pages/p3xr-settings.scss"; @import "./angular/provider/p3xr-theme.scss"; @import "./angular/ui/p3xr-accordion.scss"; @import "./angular/ui/p3xr-input.scss"; @import "./jquery/overlay.scss"; @import "./scss/vars.scss"; //injector-sass-end src/jquery/000077500000000000000000000000001520131260200131545ustar00rootroot00000000000000src/jquery/overlay.js000066400000000000000000000012341520131260200151730ustar00rootroot00000000000000let counter = 0 p3xr.ui.overlay = new function () { const template = (options = {}) => { return `
${options.hasOwnProperty('message') ? "

" : ''} ${options.hasOwnProperty('message') ? options.message : ''}
` } this.show = (options = {}) => { this.hide() //console.warn('p3xr.ui.overlay show') $body.append(template(options)) } this.hide = () => { //console.warn('p3xr.ui.overlay hide') $body.find('#p3xr-overlay').remove() } } src/jquery/overlay.scss000066400000000000000000000007321520131260200155340ustar00rootroot00000000000000 #p3xr-overlay { i { font-size: 400% !important; } font-size: 125%; position: fixed; left: 0; top: 0; width: 100vw; height: 100vh; text-align: center; /*Flexbox*/ display: flex; flex-direction: column; align-items: center; align-content: center; justify-content: center; background-color: rgba(0, 0, 0, 0.9); z-index: 99999; color: rgba(128, 128, 128, 0.5); #p3xr-overlay-info { } } src/main-development.js000066400000000000000000000003741520131260200154430ustar00rootroot00000000000000global.p3xrDevMode = true console.log('-------------------------------------') console.log(' development mode ') console.log('-------------------------------------') if (module.hot) { module.hot.accept() } require('./main') src/main.js000066400000000000000000000014751520131260200131260ustar00rootroot00000000000000require('./scss/index.scss') // fontawesome //require('@fortawesome/fontawesome-free/js/all') require('./decorate/string') global.p3xr = global.p3xr || {} p3xr.theme = { dark: undefined, light: undefined, } p3xr.ui = { overlay: undefined, htmlEncode: global.htmlEncode } require('./core/settings') require('./core/strings') require('./core/random') require('./core/is-bot') require('./core/next-id') require('./core/api') require('./core/state') require('./core/dom') require('./core/sort') require('./core/clipboard') require('./jquery/overlay') p3xr.settings.language.translation['en'] = require('./strings/en/strings') p3xr.settings.language.translation['zn'] = require('./strings/zn/strings') p3xr.settings.language.translation['ru'] = require('./strings/ru/strings') require('./angular/boot'); src/public/000077500000000000000000000000001520131260200131135ustar00rootroot00000000000000src/public/images/000077500000000000000000000000001520131260200143605ustar00rootroot00000000000000src/public/images/256x256.png000066400000000000000000000303271520131260200160340ustar00rootroot00000000000000PNG  IHDR\rfbKGD pHYs B(xtIME  ) Fm IDATxy]UsoURLd$-eAYQPA {m6QAVhʠЂaTBJԜJ%d$u|Pg^{bX,bX,bX,bX,bX,bX,bX,bX,bX,bX,@!7|4S ZVb-k,!EʜR}Zrp0}i&ZskZ`1[z#}6S$4F=ֈmk,&,}R .W)ϊ)9a X/;r눏ke>v#~__Kqz:}@_aZR$8WrOKɑˀO)O#).h / /n @xܒӵr>"`J ^xXڗ, vq&_x ՝՚"yzcDO\P.G.p%܎n k#}+NCb @$\?.[\ > Q9 5⁄=}-v8Xl+!gG䐐 uhEݣ=oci^49rv/}DE]OtOOU~]vY`nыRWjU@].WVq wJ)={G@odc#C)p׉clEe4snߧ:;zq:~mr>L*^Ez}?C/ҹ}kfg59'SWS  }qgcoTx<4:}xEzE T~gEٲcAg0:^X UYTk&>u%1&?0=΍'Ϡ޵[hL\ORwfKvZpHeE8F=pO~J#;֭wgϜI_,c<⥳?ZO|yss?uԬ/0Y+%߹s?/t>0ZJ?x&%Oz|+a#^^T \bjtOьi͏='m $`B](?*NZNDU*5xU8ɢPcż@Pg=1VqN%9fIԌudM jbenWqohCbČŔ)*_{UL{I̙]>"ETW'.Rw3ھՈ$!9frUh>CsB#XУ8Ƀk) Tw7w"Hkk\[yoS0{4̉xeW>;]IzёP p_ j^ ,)ץRuL=zM VDdx&׼JsP)3<$64 o}HM.n`o^xۅ ׹礗^_s`ZL2TvUflܹKsG,lIygov~2[>3n,080/dqI/Da jQG͒F\R:.u\5I5;z1-9|N*a?ڿ5Rӧ4$dwRl9! zV-hoabW^}K?Sb-%]?ƖN3Gaك$u2% e3uYT(AZό5|ӮSh Cj"qd\T shA}RtI͈οN)gDGf[ʧy8ET A8Bhi벸.oH'Tj:!FptIKF:tVY?@ٲb!P|B蕚)ɦ׀o5 c8aЧɷWV>gGAM+^R"_kZS8GhX+)e~j!us aH /TIQ^yto/XM(-%=4G0|[m~w0TM)Ɉet:;ݿgOA+Xpp戂ExM唲..㔲gZv.~{csbO0zB0UTЗIJ+A!UӒg< i*jz*ִ|Pu__FRz/O@+v1;1;(AXִδmXԤ/9#艂w^7܄;5ŔPQy~xOl$UPAа+bn$IYxd@IW[ 90fLusn( uu̾v5瞇ppyi^ykjC@ۧ*̷Iz^_њVLlm! 7ʩ%sOQ{GqJ@HlcZ,ROt2(u%XZuB7V]#փڻKbxeeTvէPSKDO߆6ʟ/7x_f$,,Nnݗ|ͺ%!1R9RwL}Qv1Ϛ]I3ګ>{zlr͘A{)63\E%I%( 15+-9shN7Gu4%GA{pw}R*1:CF*ƙ g<0J+jnMLs{N(G6ol Y@%~EE8EES?8Nû}mkeTWmgO#{BDӐpHU `IWfS:{=bpϠd\Υ9 '(W+5ZS*\)!+:rm a+JŠT9:ϡslk߈ᕕQ4s3g1e|Jͧx,J).[yo9KA#NkM%ҟ:4[Rm)IP98'q.gR2Sͣh,g8prRl(xSi}E0雵:}E(su J{<n~lѽ AW HD! $z.uCZܟ]`s79sޛ7ځ^k6Qy95%miI rf|n>o~h)iWuh2#:(<5^n_+:"=;7&Z3s,[.Ck27gHiRDZQ .;&ˎukv=vz`+s ~c֚v?Ht(s3^M`P-_ jǨt.y, xWi@jXHj3)n,xMdηocyiI"TB uCD"q'RTqfh5 _y?ا\6GԂ:j( ]F=<W@ C*Ǜn\q{Yp=(uԂ"4L[CQ G(+ZZޥK'nbo !(D1hX2g.~/2%'cMo#5vfK=i 7ذ1n[@[;zWP98S4\v9S.?GtWq͸v| Ƹ͝[/[{ 2Q*O.]r$Fx~'K>?0nנ\S$DgxkÆ73>gmMM!kĀlа8 5ԝw>~ƃ.57B&犩1hy3U9Ӟ}k @o/Z>2KE!h8T/i'ޓ&~=n~%\3.t+Ozy!1Ct4CŠas;/oڴ[ C%*=ƃ+8[<َ\5_-Ul2Bx?(CgWt]B)Ј{wT{. Џ)໤=4u' -q!{h:*/Fx _t GηWa?2yܗ'Y؋ pҋ&ĉ_y`b‰\а98J=b8g:nZ۟{(g'HM˼5  X}:*]A ˖ތ+pHl]:T:AU4+y~ fO@mV>J͐ ^8vO'mӰ]*cⶍ?E(hO7_*|P eAxa|XKWpj}DEIRr_KPyjJKdo4#5=ҧԻUc$fHi A+K8s7i.UNr5NWF(;x7!ug:%7 (+"*WPzPANA 3Z `Z檧܍%0Ed3 ~UHfJҿ+)EyqaKAie8ш<5Y/@\D}H toMc/5Su kͦdAW+^AQNR-iIk:םI܉1/DQ [R>}<֏J%{A+(w=fȩx]宠s$]MTeQWt~ ֠T>dXWG0+276ACq?^T9F:-瀛S3DiE̽=ƛ)ITNF\W61 (Jי3] ?jv*Y uC0@GSzd铚aaF¼c0{{+W$4%]7¥jC7{sC|EK84&\"q *ڮ8473wP۩jM[:iEАp(6,tG, A倔9*Q%RGZq'!s,5 EK3 GPySҚA*k;Id~P&RQ+11=AC+%TסT@#.JkFtpT#,u؞C[ءm N`J,|ienIT 7!P>n>S{_9Fr}A/s1)KZ%%jf^B@cw0E]E}dkk p+DuR3.s JGACCa{ 셈U,uyPiGȪcdE=Ӱ˗V2. kY&5[r^Кe~acaJx$Pxi:N#M8TffW4ɴV{{U~4h<*HbxE(3g+^P I*7P-14EjɈI|95 @o75-.>F SJ!3l!wPWZi|mXIDATLdyhIuNg %1Airj2ȱ{?uB@{hg~!?|"%G.nNιCqI`1=0K r Dƽ d]RG^7=$)Ÿ#_аgreltw~蕊>*1A+Y lB^$>۟²#/B| &eӒeJjQA?*Y3' "4u(6toFc4Feh:N>|AJ#% Eа vAUW@9)y;3ހ:OYuϡGi;bP)L[S!\#+,'i^ȼa F7vۚmd51S-iOД'O_*|P tM k-iŞҰ1峨+u߇;#0aVӰD+SWv&6En@i>Y737RZv \l8dy kx+%ْTj ؞ SbGfk:c*0 5߇ofXFIiݾzw=ĝU+:jhOˠ^g?隶%R1U\ze%LN϶lĔQ7 Ial^ v(#>`fpǂ|>|qhx'#y^9~XnviL(LL3#-![: 5O0jsAhHZU8FO\tN03Ҵfjog"fΦ2h5}R'U{ߙ|}.23)M$v|)nテ3K**A)3E$.ST}6Kh):4jI`z. r4&h8*=2GLNPk2O5QvtinSkݦupkОdL1h( jpE U JqPiJ34R3 #Ieɴ M:?GIٸ^ 2*]32hiw]JAIFkQך"Za6(m15Jt}PiG̨1d|а_j &28/JOac?ִW yrvtAV!̪VΘzQ2 ㊩}!MiZ؝ցv}(͜ Oca\U{ooZӒw(dsj=3$iE3I;&O w)٪$ ٢sq4iIAY,)mJ]|\˓ÄC mZ @zSi#w+Onlа0ԮM4Ye|Eyx`JNA=hHŚFޔ}ʦ%&ߕnq#[{`XOloPKk9w4 t%R3j䘂W4-BX0NP&w5('+qG%u/OaJk}E`xބ|7{@;5X.19h 6h}Ax \Ewf_ʏ]iS {vMM< /7W@"`D+.APR4Da:D9+|t&[ohgDKqcҥStQ{۬IA]K6P2[PU96Gb[(xmZ_b'9qܹN2K{: К^F4z.\j;|#So\[#N1ǔ&FFnpeGZWPp)6La{DHw/vj[}iӦ--KV9 XD4ܙikXd X]z#Bܫ7[v4Ã*P]AM5/_ZQ_T35~iV epY`Avݫ&`f +׶>RbS2YR5N`ZaV('&Z -OWT? K&+||L *Mg ʫv י i[HxJ(--O&7+ʦS3^05h8WJuxH(u94"[/"-CY{xP*74(7)2u?'j2aZC Vw .Ŏ2WpQ޶NK7mНXΤjr-ħZ`Q\ ǓAq|'dޘIAۄhi/W_t.2ps+55K2,:cRBsu/rkS<W k*.ԠhL8d h!~m_\B>H^s' Vlа.ӥ-l=78gp1)Ժ qJC[ZWw{m-BSͶ3MpՁIg< !VN_K 3zEʊb4,PrCx<֚[:/kaxBŋG뀏8zQ]H;ՏED +_z#ACTϥ5 *Mk:5*)+ϯ^ %q :As R-H xL*u --/Dqs =q k@kz2;;}ߡ } ۢ]FU kǹ82ܷFѰWtT=BnnnNxI4,wr:Z'5R1(#/++Wl[bDq :Ja8bBAj͐ HMqHBHߺnw!IHk0KBW &M Ou'1&),Xuk+2,q@ bu?c# ˸Lkct$O\~z;8 #>[n9:z ogG jg a-ʱ0njs4 CRUж ܾxqgiB{k<ӗd.#RX7ћ}ַ#b @ >9bÆWpX`͝[$Wj8ŽȤ)Ί.;ͧUmvt;͋ⲲR{o @\K,R~ 2E9DqPn#Ol5 Np"ķ]6[X04w+n5b|PjՊ օ up9PKk!aXÝMI$D뀹!3)?߸iSXxжhѹhW4$Nߺaݺ65/^k} ? j!Mxׯmnn_$Ҟwz0ݠGRU5j"8 GQڅ ~;šXru>o*p{o"q_gX`1[_|~ #n @>}hi釵1@PI9<[cp,Ccb{W src/scss/000077500000000000000000000000001520131260200126105ustar00rootroot00000000000000src/scss/index.scss000066400000000000000000000227521520131260200146240ustar00rootroot00000000000000 md-toast { position: fixed !important; } .p3xr-connected-readonly-filler { height: 40px; } md-dialog.fullscreen-dialog { width: 75%; } @media (max-width:959px) { md-dialog.fullscreen-dialog { min-height: 100%; min-width: 100%; border-radius: 0; md-dialog-content { height: 100vh; md-content { height: 100%; } } } } button > md-icon { position: relative; top: -1px; } /* md-dialog md-dialog-actions { display: flex; flex-flow: row-reverse; justify-content: right; } md-dialog md-dialog-actions button { } */ .p3xr-theme-light { } .p3xr-theme-dark { ::selection { color: white; background: black; } ::-moz-selection { color: white; background: black; } /* .tree-branch-head { position: relative; top: 13px; } */ $json-status-bg-color: black; $json-status-color: white; .pico-content { background-color: grey !important; color: white !important; } .pico-modal-header { background-color: black !important; } .jsoneditor-modal a { color: black !important; } .jsoneditor-modal .jsoneditor-jmespath-label { color: black !important; } .jsoneditor-modal .jsoneditor-button-group.jsoneditor-button-group-value-asc input.jsoneditor-button-asc, .jsoneditor-modal .jsoneditor-button-group.jsoneditor-button-group-value-desc input.jsoneditor-button-desc { color: white !important; background-color: black !important; } .jsoneditor-modal table th, .jsoneditor-modal table td { color: white !important; } .pico-content textarea, .pico-content select, .pico-content input { color: white !important; background-color: rgba(0, 0, 0, 0.5) !important; } /* $json-menu-bg: #4b4b4b; $json-color: white; $json-editor-text-bg-color: #666666; $json-bg: #808080; $json-editable-bg: #808080; $json-editable-bg-focus: #b1b1b1; $json-button-focus: #868686; $jsoneditor-readonly: #acacac; $json-value-string: #00ff00; $json-value-type: #cccccc; $json-value-number: #cc8888; $json-value-boolean: #fff088; $json-value-null: #49a7fc; $json-value-invalid: white; */ div.jsoneditor-tree { background-color: black; } div.jsoneditor-value.jsoneditor-string.jsoneditor-color-value { color: white; } .jsoneditor-preview { color: $json-status-color !important; } .jsoneditor-statusbar { background-color: rgba($json-status-bg-color, 0.25) !important; color: $json-status-color !important; } div.jsoneditor, div.jsoneditor-menu { border-color: #4b4b4b } div.jsoneditor-menu { background-color: #4b4b4b } div.jsoneditor textarea.jsoneditor-text, div.jsoneditor-tree { color: #fff } div.jsoneditor-field, div.jsoneditor-value { color: #fff } table.jsoneditor-search div.jsoneditor-frame { background: grey } tr.jsoneditor-highlight, tr.jsoneditor-selected { background-color: grey } div.jsoneditor-field.jsoneditor-highlight, div.jsoneditor-field[contenteditable=true]:focus, div.jsoneditor-field[contenteditable=true]:hover, div.jsoneditor-value.jsoneditor-highlight, div.jsoneditor-value[contenteditable=true]:focus, div.jsoneditor-value[contenteditable=true]:hover { background-color: grey; border-color: grey } div.jsoneditor-field.highlight-active, div.jsoneditor-field.highlight-active:focus, div.jsoneditor-field.highlight-active:hover, div.jsoneditor-value.highlight-active, div.jsoneditor-value.highlight-active:focus, div.jsoneditor-value.highlight-active:hover { background-color: #b1b1b1; border-color: #b1b1b1 } div.jsoneditor-tree button:focus { background-color: #868686 } div.jsoneditor td.jsoneditor-separator, div.jsoneditor-readonly { color: #acacac } div.jsoneditor-value.jsoneditor-string { color: #0f8 } div.jsoneditor-value.jsoneditor-array, div.jsoneditor-value.jsoneditor-object { color: #bababa } div.jsoneditor-value.jsoneditor-number { color: #ff4040 } div.jsoneditor-value.jsoneditor-boolean { color: #ff8048 } div.jsoneditor-value.jsoneditor-null { color: #49a7fc } div.jsoneditor-value.jsoneditor-invalid { color: #fff } /* dark styling of the editor */ /* div.jsoneditor, div.jsoneditor-menu { border-color: $json-status-bg-color; } div.jsoneditor-menu { background-color: $json-status-bg-color; } div.jsoneditor-tree, div.jsoneditor textarea.jsoneditor-text { background-color: $json-editor-text-bg-color; color: $json-color; } div.jsoneditor-field, div.jsoneditor-value { color: $json-color; } table.jsoneditor-search div.jsoneditor-frame { background: $json-bg; } tr.jsoneditor-highlight, tr.jsoneditor-selected { background-color: $json-bg; } div.jsoneditor-field[contenteditable=true]:focus, div.jsoneditor-field[contenteditable=true]:hover, div.jsoneditor-value[contenteditable=true]:focus, div.jsoneditor-value[contenteditable=true]:hover, div.jsoneditor-field.jsoneditor-highlight, div.jsoneditor-value.jsoneditor-highlight { background-color: $json-editable-bg; border-color: $json-editable-bg; } div.jsoneditor-field.highlight-active, div.jsoneditor-field.highlight-active:focus, div.jsoneditor-field.highlight-active:hover, div.jsoneditor-value.highlight-active, div.jsoneditor-value.highlight-active:focus, div.jsoneditor-value.highlight-active:hover { background-color: $json-editable-bg-focus; border-color: $json-editable-bg-focus; } div.jsoneditor-tree button:focus { background-color: $json-button-focus; } // coloring of JSON in tree mode div.jsoneditor-readonly { color: $jsoneditor-readonly; } div.jsoneditor td.jsoneditor-separator { color: $jsoneditor-readonly; } div.jsoneditor-value.jsoneditor-string { color: $json-value-string; } div.jsoneditor-value.jsoneditor-object, div.jsoneditor-value.jsoneditor-array { color: $json-value-type; } div.jsoneditor-value.jsoneditor-number { color: $json-value-number; } div.jsoneditor-value.jsoneditor-boolean { color: $json-value-boolean; } div.jsoneditor-value.jsoneditor-null { color: #49a7fc; } div.jsoneditor-value.jsoneditor-invalid { color: $json-value-invalid; } */ } @import 'vars'; md-toolbar, .md-toolbar-tools { height: $toolbar-height !important; min-height: $toolbar-height !important; max-height: $toolbar-height !important; } body.p3xr-no-animation * { transition: none !important; } #p3xr-redis-ui-bootstrap { height: 100vh; } .fa, .fas, .fab, far, .svg-inline--fa { transform: scale(1.5) !important; margin-right: 5px !important; margin-left: 5px !important; } [ng-click] { cursor: pointer; } .md-button { min-width: auto; } .p3xr-md-input-container-no-bottom { margin-bottom: 0px; padding-bottom: 0px; } .p3xr-md-input-container-no-top { margin-top: 0px; padding-top: 0px; } .p3xr-md-input-container-bottom-info { opacity: 0.25; } .p3xr-typography-ellipsis { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .p3xr-theme-light { /* .p3xr-input { border-color: rgba(128, 128, 128, 0.5); } */ json-tree .key { color: black; font-weight: bold; } .p3xr-md-menu-item-selected { background-color: rgba(0, 0, 0, 0.1) !important; } } .p3xr-theme-dark { .p3xr-md-menu-item-selected { background-color: rgba(255, 255, 255, 0.1) !important; } json-tree .key { color: rgba(255, 255, 255, 0.6); font-weight: bold; } ::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ color: rgba(255, 255, 255, 0.75); } /* .p3xr-input { background-color: gray; color: white; border-color: rgba(200, 200, 200, 0.5); } */ } .p3xr-pre { font-family: 'Roboto Mono' !important; //font-weight: 500; font-size: 16px; line-height: 18px; overflow: hidden !important; //white-space: pre; // white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; white-space: pre-wrap; word-spacing: 0px; } .p3xr-not-selectable { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .p3x-margin-height { margin-bottom: $layout-padding; } @import '../injector'; input, textarea { font-family: 'Roboto' !important; // font-weight: 500; } treecontrol { font-family: 'Roboto Mono' !important; font-weight: 500 !important; } md-input-container.p3xr-md-input-container-no-bottom div.md-errors-spacer { min-height: 0px; } .p3xr-roboto-monospace * { font-family: 'Roboto Mono' !important; font-weight: 500 !important; } .p3xr-padding { padding: 8px; } .md-tooltip { background-color: black !important; color: white !important; } .md-raised:focus { outline: -webkit-focus-ring-color auto 1px; } src/scss/vars.scss000066400000000000000000000000541520131260200144570ustar00rootroot00000000000000$toolbar-height: 48px; $layout-padding: 5px;src/strings/000077500000000000000000000000001520131260200133265ustar00rootroot00000000000000src/strings/en/000077500000000000000000000000001520131260200137305ustar00rootroot00000000000000src/strings/en/strings.js000066400000000000000000000413601520131260200157630ustar00rootroot00000000000000const strings = { error: { cleared_license: 'Cleared license', invalid_license: 'Invalid license', server_error: 'Server error, please try again', }, title: { donate: 'Donate', jsonRecursive: 'Expanding all leafs', name: 'P3X Redis UI', nameDonated: 'P3X Redis UI+', main: 'You may choose a Redis connection to connect from the left bottom menu.', statistics: 'Statistics', error: 'Error', connectingRedis: 'Connecting to Redis ...', socketioConnectError: 'Socket.IO Error', db: 'DB', server: 'Server', clients: 'Clients', memory: 'Memory', persistence: 'Persistance', stats: 'Statistics', replication: 'Replication', cpu: 'CPU', cluster: 'Cluster', }, confirm: { title: 'Confirm', alert: 'Alert', info: 'Info', deleteListItem: 'Are you sure to delete this list item?', deleteHashKey: 'Are you sure to delete this hash key item?', deleteStreamTimestamp: 'Are you sure to delete this stream timestamp?', deleteSetMember: 'Are you sure to delete this set member?', deleteZSetMember: 'Are you sure to delete this sorted set member?', deleteConnection: 'Confirm', deleteConnectionText: 'Are you sure to delete this Redis connection?', deleteNode: 'Are you sure to delete this Redis node?', deleteAllKeys: (opts) => { return `Delete this tree and all it\'s keys (${opts.key})?` }, socketioConnectError: 'Socket.IO cannot connect to the server, you can reload and try resolve the connection error yourself, the client does not know how to solve it itself.', deleteKey: 'Are you sure to delete this key?', rename: { title: 'Are you sure to rename this key?', textContent: 'If you click the rename button, it will rename this key forever.', placeholder: 'The Redis key (required)', }, ttl: { title: 'Are you sure to change this keys\'s TTL?', textContent: 'If you click the change TTL button, it will rename this key\'s time to live, empty will persist this key keep forever.', placeholder: 'The Redis key\'s TTL (integer or empty)', placeholderPlaceholder: 'Empty means it persists forever, otherwise the used integer.', convertTextToTime: 'Convert text to time', convertTextToTimePlaceholder: 'Eg. 1d will be 86400', }, license: { title: 'Enable donated license?', textContent: 'If you want to use the donated functions, please contact alabard@gmail.com to request a license. The donation is $1/month.', placeholder: 'License key', }, }, language: { // When you translate the english name, keep the Language in English // eg. Inglés / English en: 'English', zn: '中文 / Chinese', ru: 'Русский / Russian' }, intention: { copy: 'Copy', saveWithFormatJson: 'Save with format', formatJson: 'Format Json', pubsubMonitor: 'PubSub Monitor', // When you translate the language, keep the Language in English // eg. Idioma / Language language: 'Language', ok: 'OK', addKey: 'Add to this key', addKeyRoot: 'Add a root key', reloadKey: 'Reload key', reload: 'Reload', close: 'Close', commands: 'Commands', view: 'View', statistics: 'Statistics', refresh: 'Refresh', clear: 'Clear', rename: 'Rename', main: 'Home', cancel: 'Cancel', theme: 'Theme', github: 'GitHub', githubRepo: 'Repository', githubRelease: 'Releases', githubChangelog: 'Change log', settings: 'Settings', connect: 'Connect', disconnect: 'Disconnect', overview: 'Overview', console: 'Console', noConnections: 'No connections, add a connection in the settings menu.', noConnectionsInSettings: 'No connections, you may add a NEW CONNECTION above.', connectionAdd: 'New connection', extend: 'Extend', collapse: 'Collapse', add: 'Add', edit: 'Edit', save: 'Save', ttl: 'Set TTL', license: 'Set license', 'delete': 'Delete', remove: 'Remove', 'sure': 'Sure', testConnection: 'Test connection', getKey: 'Loading Redis key and associated data ...', jsonViewShow: 'Display JSON', jsonViewEditor: 'Edit JSON', }, label: { streamValue: `Stream field and value is a oneliner. Eg.: field1 value1 "field 2" "value 2"`, streamTimestampId: `'*' means auto generated or the specification as -`, unableToLoadKey: ({ key }) => { return `Unable to load this key: ${key}. Possible, the key was deleted. The exact error is in the console.` }, bigJson: 'This JSON object is over 10 kb, so make sure you know what you doing, because some functions can be slow rendering.', addNode: 'Add node', validateJson: 'Validate JSON', reducedFunction: `Reduced functionality`, tooManyKeys: (opts) => { return `For the full maximum functions allowed keys total is ${opts.maxLightKeysCount} count. This database has over the allowed keys in total ${opts.count}. The key sorting and the additional fancy tree information is disabled. The searching is happening only on the server instead the client search.`; }, redisCommandNotFound: 'No Redis command match found ...', treeKeyStore: `The sorting (natural compare) is executed on the client aka the browser, which means it has a penalty for big large sets, like over 10k keys, it might add a little time to the page rendering. There is no key sorting in Redis, only like this.`, socketIoTimeout: (options) => { return `The Socket.IO timed out for this request (max ${options.timeout / 1000} seconds) ...`; }, resizerInfo: (options) => { return `Left or right panel minimum width is ${options.width}px` }, jsonViewNotParsable: 'This value is not JSON parsable ', ttlTitle: 'Set the TTL in seconds', passwordSecure: 'The password might will be empty, but still it will show characters, this is a security feature.', tlsWithoutCert: 'Enable TLS without additional certificate', tlsRejectUnauthorized: 'Reject unauthorized certificate', tlsSecure: 'If you see a TLS configuration that starts with a P3X or all the TLS settings look like the same, it is a secure feature. To change the settings, just replace these settings with empty or something else and they will be saved. If you do not change the TLS settings, the settings will be kept as they are on the server.', treeSeparatorEmpty: 'If the tree separator is empty, the tree wil have no nested nodes, just a pure list', treeSeparatorEmptyNote: 'No nested nodes, just a pure list', welcomeConsole: 'Welcome to the Redis Console', welcomeConsoleInfo: 'Cursor UP or DOWN history is enabled', redisListIndexInfo: 'Empty to append, -1 to prepend or save it to the position shown.', console: 'Console', connectiondAdd: 'Add connection', connectiondEdit: 'Edit connection', connectiondView: 'View connection', connections: 'Connections', keysSort: { on: 'Key sorting on', off: 'Key sorting off' }, cluster: { on: 'Cluster on', off: 'Cluster off', }, readonly: { on: 'Readonly on', off: 'Readonly off', }, theme: { light: 'Light', dark: 'Dark enterprise', darkNeu: 'Dark', darkoBluo: 'Darko bluo', enterprise: 'Enterprise', redis: 'Redis', matrix: 'Matrix', }, connected: (opts) => { return `Connected: ${opts.name}` }, tree: 'Tree', }, status: { dataCopied: 'The data is in the clipboard', licenseSaved: 'License saved', nodeRemoved: 'Node removed', keyIsNotExisting: 'This key could have been deleted or expired.', keyCount: (opts) => { if (opts.keyCount === 0) { return 'No key' } else if (opts.keyCount === 1) { return '1 key' } else { return `${opts.keyCount} keys` } }, treeExpandAll: 'Expand all tree leafs, this has a cost, might take time ...', noRedisKeys: 'There are no keys in this database.', redisConnected: 'Redis connected successful', reloadingDataInfo: 'Reloading Redis data info', added: 'Added', saved: 'Updated', cancelled: 'Cancelled', deleted: 'Deleted', savedRedis: 'Redis data is saved', redisDisconnected: (opts) => { return `The current connection had an error: ${opts.error.message}` }, dbChanged: (opts) => { return `The db index set to ${opts.db}. ` }, treeDeleted: (opts) => { return `The tree key was deleted (${opts.key}).` }, deletedKey: (opts) => { return `The key was deleted (${opts.key}).` }, renamedKey: 'This key has been renamed', ttlChanged: 'This key\'s TTL has been changed', notInteger: 'This input is not an integer', persisted: 'This key is persisted forever', set: 'The key is set/added' }, code: { 'delete-connection': 'This connection was deleted, so you are disconnected to this Redis instance.', 'save-connection': 'This connection was changed, so you are disconnected to this Redis instance. You may re-connect.', 'readonly-connections': 'Connections add/save/delete are readonly only!', 'readonly-connection-mode': 'This connection is read only mode!', 'list-out-of-bounds': 'This list index is out of bounds', 'donation-ware-feature': 'This feature is present in the donation version.', 'auto-connection-failed': 'Possible, the connection was removed and the auto connection failed, because of this.', invalid_console_command: 'This command is not working via the GUI.', }, form: { error: { required: 'Required', port: 'The port is between 1-65535', invalid: 'The form is invalid' }, connection: { label: { name: 'Name', host: 'Hostname', port: 'Port', password: 'Password', username: 'Username', }, }, treeSettings: { maxValueDisplay: 'Max value display string length', maxValueDisplayInfo: 'If max value display zero, it shows everything, if it is bigger than 0, it will truncate. If it is -1, it will not show the value without edit for strings, for others, it display everything.', maxKeys: 'The max key count', maxKeysInfo: 'So that the GUI does not crash, we limit the max key count.', keyCount: () => { return `Number of keys: ${p3xr.state.keysRaw.length}` }, label: { animation: 'Use animation', noAnimation: 'No animation', jsonFormatTwoSpace: 'Format JSON with 2 spaces', jsonFormatFourSpace: 'Format JSON with 4 spaces', formName: 'Redis settings', searchModeClient: 'Client search mode', searchModeServer: 'Server search mode', searchModeStartsWith: 'Search with starts with mode', searchModeIncludes: 'Search includes mode', }, field: { treeSeparator: 'Tree separator', treeSeparatorSelector: 'Tree separator selector', page: 'Tree paging count', keyPageCount: 'Key paging count', keysSort: 'Sort the keys', searchMode: 'Search mode', searchModeStartsWith: 'Search starts with / includes' }, error: { keyPageCount: 'The key page count must be an integer between 5 - 100', page: 'The page count must be an integer between 10 - 1000', maxValueDisplay: 'The maximum display value must be an integer between -1 and 32768', maxKeys: 'The maximum key count value must be an integer between 100 and 100000', }, }, key: { label: { formName: { add: 'Add new Redis key', edit: 'Edit Redis key', append: 'Add to existing Redis key', } }, field: { streamTimestamp: 'Timestamp', key: 'Key', type: 'Type', index: 'Index', hashKey: 'Hash key', score: 'Score', value: 'Value', }, error: { streamTimestamp: 'The timestamp is required, either Redis format or as *', key: 'The key is, at least, one character', hashKey: 'The hash table key is at least one character', score: 'The sorted set score is required', value: 'The value is required', } }, main: { label: { database: 'DB', } } }, page: { overview: { noConnected: 'There is no connection to Redis.', overviewClients: 'List the connected by the count of clients', connectedCount: (opt) => { if (opt.length === 1) { return '1 client' } return `${opt.length} clients` } }, key: { label: { key: 'Key', encoding: 'Encoding', length: 'Size', ttl: 'TTL', ttlTitle: 'Time To Live', type: 'Type', ttlNotExpire: 'does not expire', lengthString: 'characters', lengthItem: 'items', actions: 'Actions', }, list: { table: { index: 'Index', value: 'Value', } }, hash: { table: { hashkey: 'Hashkey', value: 'Value', } }, set: { table: { value: 'Member' } }, zset: { table: { value: 'Member', score: 'Score', } }, stream: { table:{ timestamp: 'Timestamp ID', field: 'Field', value: 'Value', } }, }, treeControls: { settings: 'Tree settings', expandAll: 'Expand all', collapseAll: 'Collapse all', search: { search: 'Search in the keys', clear: 'Clear current search to set empty', placeholderClient: 'Search client side', placeholderServer: 'Search server side', info: 'The client side search means, that it matches the text in the search input. The server side search means, that is it like search in the keys patterns as *{search-text}*. For large search sets, it is better to use server side searching. For smaller search sets, it is better to use client side search mode.' + ` If the keys count is over ${p3xr.settings.maxLightKeysCount}, you can only search on server side.`, largeSetInfo: 'In a large set, client side searching is disabled. so right now only server side searching is possible.', infoDetails: 'To find out how the search works, please check out the settings' }, pager: { next: 'Next', prev: 'Previous', first: 'First', last: 'Last' } } }, time: { years: 'years', months: 'months', days: 'days', year: 'year', month: 'month', day: 'day', }, redisTypes: { string: 'String', list: 'List', hash: 'Hash table', set: 'Set', zset: 'Sorted set - zset', stream: 'Stream', } } module.exports = strings; src/strings/ru/000077500000000000000000000000001520131260200137545ustar00rootroot00000000000000src/strings/ru/strings.js000066400000000000000000000572711520131260200160170ustar00rootroot00000000000000const strings = { error: { cleared_license: 'Очищенная лицензия', invalid_license: 'Неверная лицензия', server_error: 'Серверная ошибка, пожалуйсто попробуйте снова', }, title: { donate: 'Донат', jsonRecursive: 'Расширяем все листья', name: 'P3X Redis UI', nameDonated: 'P3X Redis UI+', main: 'Вы можете выбрать Redis коннектор для соединения из меню снизу слева.', statistics: 'Статистика', error: 'Ошибка', connectingRedis: 'Подключаемся к Redis ...', socketioConnectError: 'Ошибка Socket.IO', db: 'База данных', server: 'Сервер', clients: 'Клиент', memory: 'Память', persistence: 'Постоянность', stats: 'Статистика', replication: 'Репликация', cpu: 'ЦПУ', cluster: 'Кластер', }, confirm: { title: 'Подтвердить', alert: 'Внимание', info: 'Информация', deleteListItem: 'Вы точно хотите удалить этот список?', deleteHashKey: 'Вы точно хотите удалить этот хэш?', deleteStreamTimestamp: 'Вы точно хотите удалить эту временную отметку потока?', deleteSetMember: 'Вы точно хотите удалить этого члена набора?', deleteZSetMember: 'Вы точно хотите удалить этого члена сортированного набора?', deleteConnection: 'Подтвердить', deleteConnectionText: 'Вы точно хотите удалить это подключение Redis?', deleteNode: 'Вы точно хотите удалить эту ноду Redis?', deleteAllKeys: (opts) => { return `Удалить это дерево и все его ключи (${opts.key})?` }, socketioConnectError: 'Socket.IO не может подключится к серверу, вы можете перезагрузить и решить проблему с соединением самостоятельно, клиент не знает как решить это.', deleteKey: 'Вы точно хотите удалить этот ключ?', rename: { title: 'Вы точно хотите переименовать этот ключ?', textContent: 'Если вы нажмёте кнопку \"Переименоват\" вы навсегда переименуете этот ключ.', placeholder: 'Ключ Redis (обязательно)', }, ttl: { title: 'Вы точно хотите изменить TTL этого ключа?', textContent: 'Если вы нажмёте \"Изменить\" вы измените TTL этого ключа, пустой TTL равен вечному.', placeholder: 'TTL ключа Redis (цельная цифра или ничего)', placeholderPlaceholder: 'Пустота означает вечность, для других случаев используйте целое число.', convertTextToTime: 'Конвертировать текст во время', convertTextToTimePlaceholder: 'Например, 1d равен 86400', }, license: { title: 'Включить лицензию донатера?', textContent: 'Если вы хотите использовать функции для донатеров, пожалуйсто запросите лицензию у alabard@gmail.com . Донат стоит $1/месяц.', placeholder: 'Ключ лицензии', }, }, language: { // When you translate the english name, keep the Language in English // eg. Inglés / English en: 'Английский / English', zn: '中文 / Chinese', ru: 'Русский / Russian' }, intention: { copy: 'Копировать', saveWithFormatJson: 'Сохранить с форматом', formatJson: 'Форматировать Json', pubsubMonitor: 'Мониторинг PubSub', // When you translate the language, keep the Language in English // eg. Idioma / Language language: 'Язык / Language', ok: 'ОК', addKey: 'Добавить к этому ключу', addKeyRoot: 'Добавить к корневому ключу', reloadKey: 'Кнопка перезагрузки', reload: 'Перезагрузить', close: 'Закрыть', commands: 'Команды', view: 'Вид', statistics: 'Статистика', refresh: 'Обновить', clear: 'Очистить', rename: 'Переименовать', main: 'Домой', cancel: 'Отмена', theme: 'Тема', github: 'GitHub', githubRepo: 'Репозиторий', githubRelease: 'Релизы', githubChangelog: 'Изменения', settings: 'Настройки', connect: 'Подключиться', disconnect: 'Отключится', overview: 'Обзор', console: 'Консоль', noConnections: 'Подключения отсутствуют, добавьте подключение в меню настроек.', noConnectionsInSettings: 'Подключения отсутствуют, вы можете добавить НОВОЕ ПОДКЛЮЧЕНИЕ выше.', connectionAdd: 'Новое подключение', extend: 'Расширить', collapse: 'Схлопнуть', add: 'Добавить', edit: 'Редактировать', save: 'Сохранить', ttl: 'Выбрать TTL', license: 'Выбрать лицензию', 'delete': 'Удалить', remove: 'Убрать', 'sure': 'Хорошо', testConnection: 'Проверка соединения', getKey: 'Загрузка ключа Redis и асоциированных данных ...', jsonViewShow: 'Показать JSON', jsonViewEditor: 'Редактировать JSON', }, label: { streamValue: `Поле и значение потока это однополосник. Например: поле1 значение1 "поле 2" "значение 2"`, streamTimestampId: `'*' означает автогенерацию или определяется как -`, unableToLoadKey: ({ key }) => { return `Не вышло загрузить ключ: ${key}. Возможно он был удалён. Полная ошибка написана в консоли.` }, bigJson: 'Этот JSON обьект больше 10 kb, удостоверьтесь что вы знаете что делаете, так как некоторые функции рендерятся медленнее.', addNode: 'Добавить ноду', validateJson: 'Проверить JSON', reducedFunction: `Урезанная функциональность`, tooManyKeys: (opts) => { return `Для полноценной работы максимума функций разрешены ключи в общем количестве ${opts.maxLightKeysCount} штук. Эта база данных имеет больше ключей чем разрешено, суммой ${opts.count}. Сортировка и информация древом для ключей выключены. Поиск будет производится только на серверной стороне.`; }, redisCommandNotFound: 'Ни одна команда Redis не совпадает с вводом ...', treeKeyStore: `Сортировка (природное сравнение) выполняется в клиенте (он же браузер), что замедляет большие сортировки, например больше чем 10k ключей, это может добавить немного задержки к прогрузке страницы. В самом Redis нету сортировки ключей, это можно делать только так.`, socketIoTimeout: (options) => { return `Socket.IO не успел ответить на запрос (максимум ${options.timeout / 1000} секунд) ...`; }, resizerInfo: (options) => { return `Минимальная ширина левой или правой панели это ${options.width}px` }, jsonViewNotParsable: 'Это значение не подобно JSON', ttlTitle: 'Выбрать TTL в секундах', passwordSecure: 'Пароль может быть пустым, но он всё ещё будет отображать символы, это фича для безопасности.', tlsWithoutCert: 'Включить TLS без дополнительного сертификата', tlsRejectUnauthorized: 'Reject unauthorized certificate', tlsSecure: 'Если вы видите TLS конфигурацию которая начинается с P3X или все настройки TLS выглядят одинаково, это фича для безопасности. Для изминения настроек надо заменить эти настройки пустыми или чем либо ещё, и они сохранятся. Если вы ек измените настройки TLS, настройки останутся такими же как и на самом сервере.', treeSeparatorEmpty: 'Если разделитель дерева пуст, в дереве вместо вложенных нод будет лишь чистый список', treeSeparatorEmptyNote: 'Никаких вложенных нод, только чистый список', welcomeConsole: 'Добро пожаловать в консоль Redis', welcomeConsoleInfo: 'История по нажатию ВВЕРХ или ВНИЗ кллючена', redisListIndexInfo: 'Пустое для добавления, -1 что бы сделать вид или сохранить в указанную позицию.', console: 'Консоль', connectiondAdd: 'Добавить соединение', connectiondEdit: 'Изменить соединение', connectiondView: 'Осмотреть соединение', connections: 'Соединения', keysSort: { on: 'Сортировка ключей включена', off: 'Сортировка ключей выключена' }, cluster: { on: 'Кластеризация активирована', off: 'Кластеризация деактивирована', }, readonly: { on: 'Режим \"только чтение\"', off: 'Режим \"редактирование\"', }, theme: { light: 'Светлая', dark: 'Тёмная корпоративная', darkNeu: 'Тёмная', darkoBluo: 'Тёмное синево', enterprise: 'Корпоративная', redis: 'Redis', matrix: 'Матрица', }, connected: (opts) => { return `Подключено: ${opts.name}` }, tree: 'Дерево', }, status: { dataCopied: 'Данные скопированы в буфер обмена', licenseSaved: 'Лицензия сохранена', nodeRemoved: 'Нода удалена', keyIsNotExisting: 'Этот ключ вероятно был удалён или истёк.', keyCount: (opts) => { if (opts.keyCount === 0) { return 'Нету ключей' } else if (opts.keyCount === 1) { return '1 ключ' } else { return `${opts.keyCount} ключей` } }, treeExpandAll: 'Развернуть все листья дерева, это имеет цену, временную ...', noRedisKeys: 'Нету ключей в базе данных.', redisConnected: 'Redis успешно подключен', reloadingDataInfo: 'Перезагружаем информацию о данных Redis', added: 'Добавлено', saved: 'Обновлено', cancelled: 'Отменено', deleted: 'Удалено', savedRedis: 'Данные Redis были сохранены', redisDisconnected: (opts) => { return `Произошла ошибка в теперешнем соединении: ${opts.error.message}` }, dbChanged: (opts) => { return `Выбран индекс базы данных ${opts.db}. ` }, treeDeleted: (opts) => { return `Ключ дерева был удалён (${opts.key}).` }, deletedKey: (opts) => { return `Ключ был удалён (${opts.key}).` }, renamedKey: 'Этот ключ был переименован', ttlChanged: 'TTL этого ключа был изменён', notInteger: 'Этот ввод не для цельной цифры', persisted: 'Этот ключ не исчезнет сам', set: 'Этот ключ был применён/добавлен' }, code: { 'delete-connection': 'Это соединение было удалено и по этому вы были отключены от этой инстанции Redis.', 'save-connection': 'Это подключение было изменено и по этому вы были отключены от этой инстанции Redis. Вы можете переподключится.', 'readonly-connections': 'Добавление/сохранение/удаление соединений в режиме \"только чтение\"!', 'readonly-connection-mode': 'Это соединение в режиме \"только чтение\"!', 'list-out-of-bounds': 'Индекс этого списка вышел за границы', 'donation-ware-feature': 'Эта функция доступна в донатерской версии.', 'auto-connection-failed': 'Вероятно, соединение было удалено и авто-соединение провалилось по таковой причине.', invalid_console_command: 'Эта команда не работает через GUI.', }, form: { error: { required: 'Обязательно', port: 'Порт в границах 1-65535', invalid: 'Форма заполнена неверно' }, connection: { label: { name: 'Название', host: 'Имя хоста', port: 'Порт', password: 'Пароль', username: 'Имя пользователя', }, }, treeSettings: { maxValueDisplay: 'Длинна видимой строки', maxValueDisplayInfo: 'Если значение длинны показа равно нулю, будет показано всё, если же оно больше - вывод будет урезан. Если он равен минус одному, вывод будет скрыт до начала редактирования для строк, для других же типов будет показано всё.', maxKeys: 'Максимум символов', maxKeysInfo: 'Максимум ключей ограничен что бы GUI не падал.', keyCount: () => { return `Количество ключей: ${p3xr.state.keysRaw.length}` }, label: { animation: 'Использовать анимацию', noAnimation: 'Выключить анимацию', jsonFormatTwoSpace: 'Форматировать JSON двумя пробелами', jsonFormatFourSpace: 'Форматировать JSON четырьмя пробелами', formName: 'Настройки Redis', searchModeClient: 'Клиентский режим поиска', searchModeServer: 'Серверный режим поиска', searchModeStartsWith: 'Поиск начала', searchModeIncludes: 'Поиск содержимого', }, field: { treeSeparator: 'Разделитель дерева', treeSeparatorSelector: 'Избиратель разделителя дерева', page: 'Счётчик количества страниц', keyPageCount: 'Счётчик количества ключей', keysSort: 'Сортировка ключей', searchMode: 'Режим поиска', searchModeStartsWith: 'Поиск начинается с / содержит' }, error: { keyPageCount: 'Ограничитель показа ключей на странице должен быть цельным числом в границах 5 - 100', page: 'Ограничитель показа страниц должен быть цельным числом в границах 10 - 1000', maxValueDisplay: 'Максимальное количество показываемых значений должен быть цельным числом между -1 и 32768', maxKeys: 'Максимальное количество показываемых ключей должен быть цельным числом между 100 и 100000', }, }, key: { label: { formName: { add: 'Добавить новый ключ Redis', edit: 'Редактировать ключ Redis', append: 'Добавить к существующему ключу Redis', } }, field: { streamTimestamp: 'Временная отметка', key: 'Ключ', type: 'Тип', index: 'Индекс', hashKey: 'Хэш', score: 'Очки', value: 'Значение', }, error: { streamTimestamp: 'Временная отметка обязательна, либо в формате Redis либо как *', key: 'Ключ должен иметь длинну минимум одного символа', hashKey: 'Стол хэшей ключей должен иметь длинну минимум одного символа', score: 'Очки сортировки набора обязательны', value: 'Значение обязательно', } }, main: { label: { database: 'База данных', } } }, page: { overview: { noConnected: 'Нету подключения к Redis.', overviewClients: 'Показать подключения по количеству клиентов', connectedCount: (opt) => { if (opt.length === 1) { return '1 клиент' } return `${opt.length} клиентов` } }, key: { label: { key: 'Ключ', encoding: 'Кодировка', length: 'Размер', ttl: 'TTL', ttlTitle: 'Время На Жизнь (TTL)', type: 'Тип', ttlNotExpire: 'не истекает', lengthString: 'символы', lengthItem: 'обьекты', actions: 'Действия', }, list: { table: { index: 'Индекс', value: 'Значение', } }, hash: { table: { hashkey: 'Хэш', value: 'Значение', } }, set: { table: { value: 'Член' } }, zset: { table: { value: 'Член', score: 'Очки', } }, stream: { table:{ timestamp: 'Идентификатор временной отметки', field: 'Поле', value: 'Значение', } }, }, treeControls: { settings: 'Настройки дерева', expandAll: 'Развернуть все', collapseAll: 'Свернуть все', search: { search: 'Поиск ключа', clear: 'Очистить теперешний поиск', placeholderClient: 'Искать в клиенте', placeholderServer: 'Искать на сервере', largeSetInfo: 'In a large set, client side searching is disabled. so right now only server side searching is possible.', info: 'Поиск в клиенте означает совпадание с содержимым поля поиска. Серверный поиск означает поиск паттерном на подобие *{искомый-текст}*. Для поиска больших наборов лучше использовать серверный поиск. Для меньших поисковых наборов лучше использовать поиск клиентом.' + ` Если количество ключей превышает ${p3xr.settings.maxLightKeysCount}, можно будет искать только серверным поиском.`, infoDetails: 'Что бы понять как поиск работает, изучите настройки' }, pager: { next: 'Следующий', prev: 'Предыдущий', first: 'Первый', last: 'Последний' } } }, time: { years: 'года', months: 'месяца', days: 'дни', year: 'год', month: 'месяц', day: 'день', }, redisTypes: { string: 'Строка', list: 'Список', hash: 'Стол хэшей', set: 'Набор', zset: 'Сортированный набор - zset', stream: 'Поток', } } module.exports = strings; src/strings/zn/000077500000000000000000000000001520131260200137555ustar00rootroot00000000000000src/strings/zn/strings.js000066400000000000000000000376351520131260200160220ustar00rootroot00000000000000const strings = { error: { cleared_license: '清除许可证', invalid_license: '无效的许可证', server_error: '服务器错误,请重试', }, title: { donate: '捐赠', jsonRecursive: '展开所有叶子', name: 'P3X Redis UI', nameDonated: 'P3X Redis UI+', main: '您可以从左下方菜单中选择要连接的Redis进行连接访问', statistics: 'Statistics', error: '错误', connectingRedis: '连接到Redis ...', socketioConnectError: 'Socket.IO 错误', db: 'DB', server: '服务端', clients: '客户端', memory: '内存', persistence: '持久性', stats: '统计', replication: '同步复制', cpu: 'CPU', cluster: '集群', }, confirm: { title: '确认', alert: '警告', info: '信息', deleteListItem: '您确定要删除该列表项吗?', deleteHashKey: '您确定要删除该哈希键项吗?', deleteStreamTimestamp: '您确定要删除此流时间戳吗?', deleteSetMember: '您确定要删除该集合成员?', deleteZSetMember: '您确定要删除该有序集合成员?', deleteConnection: '确认', deleteConnectionText: '您确定要删除此Redis连接吗?', deleteNode: '您确定要删除此Redis节点吗?', deleteAllKeys: (opts) => { return `删除此树及其所有键 (${opts.key})?` }, socketioConnectError: 'Socket.IO 不能连接到该服务, 您可以重新加载及尝试自己解决该错误, 客户端自身无法解决该错误', deleteKey: '您确定要删除这个键吗?', rename: { title: '您确定要重命名该键名么?', textContent: '如果您点击重命名按钮,它将永久重命名此键。', placeholder: '该Redis键(必须存在)', }, ttl: { title: '您要改变该键的TTL吗?', textContent: '如果您点击更改TTL按钮, 会改变该键的生存时间,设置为空则有效期永久', placeholder: 'Redis键的TTL(整数或空)', placeholderPlaceholder: '空意味着它将永久存在,否则将使用所使用的整数。', convertTextToTime: '将文字转换为时间', convertTextToTimePlaceholder: '例如。 1d将是86400', }, license: { title: '启用捐赠的许可证?', textContent: '如果要使用捐赠的功能,请联系alabard@gmail.com申请许可证。 捐款是每月1美元。', placeholder: '注册码', }, }, language: { en: '英语 / English', zn: '中文 / Chinese', ru: 'Русский / Russian' }, intention: { copy: '复制', saveWithFormatJson: '保存格式', formatJson: '格式化Json', pubsubMonitor: 'PubSub监视器', language: '语言 / Language', ok: '确定', addKey: '加入此键', addKeyRoot: '加入一个根键', reloadKey: '重载键', reload: '重载', close: '关闭', commands: '命令', view: '视图', statistics: '统计', refresh: '刷新', clear: '清除', rename: '重命名', main: '主页', cancel: '取消', theme: '主题', github: 'GitHub', githubRepo: '仓库', githubRelease: '发布', githubChangelog: '更新日志', settings: '设置', connect: '连接', disconnect: '断开', overview: '概览', console: '控制台', noConnections: '没有任何连接,请在设置菜单中添加一个连接。', noConnectionsInSettings: '没有连接,您可以在上面添加一个新的连接。', connectionAdd: '新连接', extend: '拓展', collapse: '折叠', add: '添加', edit: '编辑', save: '保存', ttl: '设置 TTL', license: '设定牌照', 'delete': '删除', remove: '删除', 'sure': '确定', testConnection: '测试连接', getKey: '加载Redis键及相关数据...', jsonViewShow: '显示 JSON 树', jsonViewEditor: '编辑JSON', }, label: { streamValue: `流字段和值是唯一的。 例如:field1 value1 "field 2" "value 2"`, streamTimestampId: `'*'表示自动生成或指定为-`, unableToLoadKey: ({ key }) => { return `无法加载此密钥:: ${key}。可能,密钥被删除了。确切的错误在控制台中。` }, bigJson: '此JSON对象超过10 kb,因此请确保您知道自己在做什么,因为某些功能可能会缓慢呈现。', addNode: '添加节点', validateJson: '验证JSON', reducedFunction: `功能限制`, tooManyKeys: (opts) => { return `对于最大函数允许的键个数为 ${opts.maxLightKeysCount}. 该数据库允许共超过的键总数为 ${opts.count}.但键的排序及范式树等相关信息会被禁用。搜索仅在服务器上进行,而不是客户端搜索。`; }, redisCommandNotFound: '找不到匹配的Redis命令...', treeKeyStore: `该排序(自然排序)运行在客户端的浏览器上, 意味着针对大型集合(例如超过1W个键),渲染的时长开销需要增加.Redis中没有键排序, 就像这样。`, socketIoTimeout: (options) => { return `Socket.IO 请求超时,请求时最长(最大 ${options.timeout / 1000}秒) ...`; }, resizerInfo: (options) => { return `面板(左/右)的最小宽度是 ${options.width}像素` }, jsonViewNotParsable: '该值JSON无法解析', ttlTitle: '设置TTL时间(秒)', passwordSecure: '密码可能为空,但仍会显示字符,这是一项安全功能。', treeSeparatorEmpty: '如果树分隔符为空,则树将没有嵌套节点,只有纯列表', tlsWithoutCert: '无需额外证书即可启用 TLS', tlsRejectUnauthorized: '拒绝未经授权的证书', tlsSecure: '如果您看到以 P3X 开头的 TLS 配置或所有 TLS 设置看起来都相同,则这是一项安全功能。 要更改设置,只需将这些设置替换为空或其他内容即可保存。 如果您不更改 TLS 设置,这些设置将保持在服务器上的原样。', treeSeparatorEmptyNote: '没有嵌套节点,只是一个纯列表', welcomeConsole: '欢迎来到Redis控制台', welcomeConsoleInfo: '上下方向键选择历史记录功能已启用', redisListIndexInfo: '空值追加, -1 到前置或保存到光标之处', console: '控制台', connectiondAdd: '添加连接', connectiondEdit: '编辑连接', connectiondView: '查看连接', connections: '连接', keysSort: { on: '开启键排序', off: '关闭键排序' }, cluster: { on: '群集', off: '集群关闭', }, readonly: { on: '只读', off: '只读关闭', }, theme: { light: '浅棕', dark: '黑暗企业', darkNeu: '暗色', darkoBluo: '蓝色', enterprise: '企业风', redis: 'Redis风格', matrix: '矩阵', }, connected: (opts) => { return `已连接: ${opts.name}` }, tree: '树', }, status: { dataCopied: '数据在剪贴板中', licenseSaved: '许可证已保存', nodeRemoved: '节点已删除', keyIsNotExisting: '此键可能已被删除或过期。', keyCount: (opts) => { if (opts.keyCount === 0) { return '没有任何键' } else if (opts.keyCount === 1) { return '1 个键' } else { return `${opts.keyCount} 键` } }, treeExpandAll: '展开所可能的原因是,连接已删除,自动连接失败有树,该操作的代价就是有点费时...', noRedisKeys: '此数据库中没有任何键。', redisConnected: 'Redis 连接成功', reloadingDataInfo: '重新加载Redis数据信息', added: '已添加', saved: '已更新', cancelled: '已取消', deleted: '已删除', savedRedis: 'Redis数据已保存', redisDisconnected: (opts) => { return `该连接有一个错误: ${opts.error.message}` }, dbChanged: (opts) => { return `db索引设置为 ${opts.db}. ` }, treeDeleted: (opts) => { return `该树已删除 (${opts.key}).` }, deletedKey: (opts) => { return `该键已删除 (${opts.key}).` }, renamedKey: '该键已重命名', ttlChanged: '该键TTL已被更改', notInteger: '输入值不是一个整数', persisted: '永久键', set: '键已设置/添加' }, code: { 'delete-connection': '此连接已删除,因此您与此Redis实例断开连接。', 'save-connection': '此连接已更改,因此您与此Redis实例断开连接。 你可以重新连接。', 'readonly-connections': '连接(添加/保存/删除)只是只读!', 'readonly-connection-mode': '此连接为只读模式!', 'list-out-of-bounds': '此列表索引超出范围', 'donation-ware-feature': '捐赠版本中提供了此功能。', 'auto-connection-failed': '因此,可能导致连接被删除并且自动连接失败。', invalid_console_command: '此命令无法通过 GUI 运行。', }, form: { error: { required: '必填', port: '端口号范围是 1-65535', invalid: '值无效,请重新输入' }, connection: { label: { name: '连接名字', host: '主机名', port: '端口', password: '密码', username: '用户名', }, }, treeSettings: { maxValueDisplay: '最大值显示字符串长度', maxValueDisplayInfo: '如果最大值显示为零,则显示所有内容,如果大于0,则将截断。 如果它是-1,它将不显示没有编辑字符串的值,对于其他人,它显示所有内容。', maxKeys: '最大密钥数', maxKeysInfo: '为了避免GUI崩溃,我们限制了最大密钥数。', keyCount: () => { return `键数: ${p3xr.state.keysRaw.length}` }, label: { animation: '使用动画', noAnimation: '没有动画', jsonFormatTwoSpace: '用2个空格格式化JSON', jsonFormatFourSpace: '用4个空格格式化JSON', formName: 'Redis设置', searchModeClient: '客户端搜索模式', searchModeServer: '服务端搜索模式', searchModeStartsWith: '以模式启动搜索', searchModeIncludes: '搜索包括模式', }, field: { treeSeparator: '树分隔符', treeSeparatorSelector: '树分隔符选择器', page: '树分页数', keyPageCount: '按键分页数', keysSort: '对键进行排序', searchMode: '搜索模式', searchModeStartsWith: '搜索以 / 开头' }, error: { keyPageCount: '密钥页数必须为5到100之间的整数', page: '页数必须是10 - 500之间的整数', maxValueDisplay: '最大显示值必须是介于-1和32768之间的整数', maxKeys: '最大密钥计数值必须是100到100000之间的整数', }, }, key: { label: { formName: { add: '添加新的Redis键', edit: '编辑 Redis key', append: '添加到现有的Redis键', } }, field: { streamTimestamp: '时间戳记', key: '键', type: '类型', index: '索引', hashKey: '哈希键', score: '分数', value: '值', }, error: { streamTimestamp: '时间戳是必需的,可以是Redis格式,也可以*', key: '键至少存在一个字符', hashKey: '哈希表键至少是一个字符', score: '排序的集合分数是必需的', value: '该值是必填的', } }, main: { label: { database: 'DB', } } }, page: { overview: { noConnected: '没有任何连接到Redis', overviewClients: '按客户端连接计数展示所有连接', connectedCount: (opt) => { if (opt.length === 1) { return '1 客户端' } return `${opt.length} 客户端` } }, key: { label: { key: '键', encoding: '编码', length: '大小', ttl: 'TTL', ttlTitle: '生存时间', type: '类型', ttlNotExpire: '不会过期', lengthString: '字符', lengthItem: '项数', actions: '操作', }, list: { table: { index: '索引', value: '值', } }, hash: { table: { hashkey: '哈希', value: '值', } }, set: { table: { value: '成员' } }, zset: { table: { value: '成员', score: '分数', } }, stream: { table:{ timestamp: '时间戳ID', field: '领域', value: '值', } }, }, treeControls: { settings: '树设置', expandAll: '展开所有', collapseAll: '折叠所有', search: { search: '在键中搜索', clear: '清空当前搜索结果', placeholderClient: '客户端搜索', placeholderServer: '服务端搜索', info: `客户端搜索是匹配输入的文本,服务端搜索则遵循*{search-text}*模式搜索.对于大量数据的搜索最好在服务端进行搜索,而较小数据量可以考虑客户端搜索。如果键数超过 ${p3xr.settings.maxLightKeysCount}个的则只能在服务端搜索`, largeSetInfo: '在大型集合中,禁用客户端搜索。 所以现在只能进行服务器端搜索。', infoDetails: '要了解搜索的工作原理,请查看设置' }, pager: { next: '下一页', prev: '上一页', first: '首页', last: '末页' } } }, time: { years: '年份', months: '个月', days: '天', year: '年', month: '月', day: '天', }, redisTypes: { string: '字符串', list: '列表', hash: '哈希表', set: '集合', zset: '有序集合 - zset', stream: '流', } } module.exports = strings; src/vendor.js000066400000000000000000000021701520131260200134700ustar00rootroot00000000000000require('./vendor.scss') // jquery global.$ = require('jquery/dist/jquery.slim') global.jQuery = global.$ jQuery.event.special.touchstart = { setup: function( _, ns, handle ){ if ( ns.includes("noPreventDefault") ) { this.addEventListener("touchstart", handle, { passive: false }); } else { this.addEventListener("touchstart", handle, { passive: true }); } } }; // moment global.moment = require('moment') require('moment/locale/zh-cn') global.$window = $(window); $(() => { global.$body = $('body'); }) global.htmlEncode = require('js-htmlencode').htmlEncode // socket global.io = require('socket.io-client/dist/socket.io.js') // angular global.angular = require('angular'); require('angular-aria'); require('angular-sanitize') require('angular-messages'); require('angular-animate'); require('angular-cookies'); require('angular-inview') require('@uirouter/angularjs') require('angular-material'); require('angular-tree-control') //require('angular-tree-control/context-menu') // angular context menu fix angular.module("contextMenu", []); require('angular-json-tree') src/vendor.scss000066400000000000000000000013721520131260200140320ustar00rootroot00000000000000@import '~material-design-icons-iconfont/dist/material-design-icons.css'; @import '~angular-material/angular-material.css'; @import '~angular-tree-control/css/tree-control.css'; @import '~angular-json-tree/dist/angular-json-tree.css'; @import '~@fortawesome/fontawesome-free/css/all.min.css'; @import '~@fontsource/roboto/300.css'; @import '~@fontsource/roboto/400.css'; @import '~@fontsource/roboto/400-italic.css'; @import '~@fontsource/roboto/500.css'; @import '~@fontsource/roboto/700.css'; @import '~@fontsource/roboto-mono/300.css'; @import '~@fontsource/roboto-mono/400.css'; @import '~@fontsource/roboto-mono/400-italic.css'; @import '~@fontsource/roboto-mono/500.css'; @import '~@fontsource/roboto-mono/700.css'; @import "~angular/angular-csp.css";