diff --git a/.gitignore b/.gitignore index c1e62bc38..ffa9d8b97 100644 --- a/.gitignore +++ b/.gitignore @@ -36,7 +36,7 @@ runtime/pgAdmin4_resource.rc runtime/release/ runtime/ui_BrowserWindow.h web/config_local.py -web/pgadmin.themes.json +web/pgadmin/misc/themes/pgadmin.themes.json web/geckodriver.log web/regression/test_config.json node_modules/ diff --git a/web/config.py b/web/config.py index f992cc487..d7802d695 100644 --- a/web/config.py +++ b/web/config.py @@ -487,25 +487,6 @@ try: except ImportError: pass -THEMES = { - "standard": { - "disp_name": "Standard", - "cssfile": "pgadmin", - "preview_img": "standard_preview.png" - } -} - -OTHER_THEMES = {} -try: - extra_themes = json.load(open('pgadmin.themes.json')) - OTHER_THEMES.update(extra_themes) -except Exception: - pass - -# Set OTHER_THEMES to None here to disable all other themes - -if OTHER_THEMES is not None: - THEMES.update(OTHER_THEMES) # SUPPORT_SSH_TUNNEL can be override in local config file and if that # setting is False in local config then we should not check the Python version. diff --git a/web/pgadmin.themes.json b/web/pgadmin.themes.json new file mode 100644 index 000000000..5fb853ad8 --- /dev/null +++ b/web/pgadmin.themes.json @@ -0,0 +1,7 @@ +{ + "dark": { + "disp_name": "dark_(Beta)", + "cssfile": "pgadmin.theme.dark", + "preview_img": "dark_preview.png" + } +} \ No newline at end of file diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py index 41ca051f1..8a38c0ad0 100644 --- a/web/pgadmin/__init__.py +++ b/web/pgadmin/__init__.py @@ -711,28 +711,18 @@ def create_app(app_name=None): from flask_compress import Compress Compress(app) + from pgadmin.misc.themes import Themes + Themes(app) + @app.context_processor def inject_blueprint(): """ Inject a reference to the current blueprint, if any. - Also the get_theme_css func. """ - def get_theme_css(): - misc_preference = Preferences.module('misc') - theme = misc_preference.preference('theme').get() - theme_css = config.THEMES['standard']['cssfile'] + '.css' - - if theme not in config.THEMES: - pass - else: - theme_css = config.THEMES[theme]['cssfile'] + '.css' - return theme_css - return { 'current_app': current_app, 'current_blueprint': current_blueprint, - 'get_theme_css': get_theme_css, } @app.errorhandler(Exception) diff --git a/web/pgadmin/dashboard/static/js/charting.js b/web/pgadmin/dashboard/static/js/charting.js index 3b9a4c24a..6b1395507 100644 --- a/web/pgadmin/dashboard/static/js/charting.js +++ b/web/pgadmin/dashboard/static/js/charting.js @@ -32,6 +32,10 @@ export class Chart { }, shadowSize: 0, resolution : 3, + grid: { + color: 'transparent', + tickColor: '#8f8f8f', + }, }; this._dataset = null; diff --git a/web/pgadmin/dashboard/static/scss/_dashboard.scss b/web/pgadmin/dashboard/static/scss/_dashboard.scss index 4b204a3bb..ba51650b8 100644 --- a/web/pgadmin/dashboard/static/scss/_dashboard.scss +++ b/web/pgadmin/dashboard/static/scss/_dashboard.scss @@ -43,10 +43,23 @@ & .flotr-labels { color: $color-fg !important; } - & .flotr-legend { - .flotr-legend-label { + & .flotr-legend { + border: none !important; + padding: 0.25rem 0.5rem; + & .flotr-legend-label { color: $color-fg !important; padding-left: 0.25rem; } - } + + & .flotr-legend-color-box>div { + border: none !important; + &>div { + border: none !important; + } + } + + & .flotr-legend-bg { + border-radius: $border-radius; + } + } } diff --git a/web/pgadmin/misc/__init__.py b/web/pgadmin/misc/__init__.py index 68d4381af..d0bef8e15 100644 --- a/web/pgadmin/misc/__init__.py +++ b/web/pgadmin/misc/__init__.py @@ -14,9 +14,8 @@ from flask import url_for, render_template, Response, request from flask_babelex import gettext from pgadmin.utils import PgAdminModule from pgadmin.utils.csrf import pgCSRFProtect -from pgadmin.utils.preferences import Preferences from pgadmin.utils.session import cleanup_session_files - +from pgadmin.misc.themes import get_all_themes import config MODULE_NAME = 'misc' @@ -68,16 +67,16 @@ class MiscModule(PgAdminModule): theme_options = [] - for theme in config.THEMES: + for theme, theme_data in (get_all_themes()).items(): theme_options.append({ - 'label': config.THEMES[theme]['disp_name'] + 'label': theme_data['disp_name'] .replace('_', ' ') .replace('-', ' ') .title(), 'value': theme, 'preview_src': url_for( 'static', filename='js/generated/img/' + - config.THEMES[theme]['preview_img'] + theme_data['preview_img'] ) }) diff --git a/web/pgadmin/misc/themes/__init__.py b/web/pgadmin/misc/themes/__init__.py new file mode 100644 index 000000000..301f0f665 --- /dev/null +++ b/web/pgadmin/misc/themes/__init__.py @@ -0,0 +1,49 @@ +import os +import json +from pgadmin.utils.preferences import Preferences + + +def get_all_themes(): + theme_file_path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + 'pgadmin.themes.json' + ) + + all_themes = { + "standard": { + "disp_name": "Standard", + "cssfile": "pgadmin", + "preview_img": "standard_preview.png" + } + } + + try: + all_themes.update(json.load(open(theme_file_path))) + except Exception as _: + pass + + return all_themes + + +def Themes(app): + @app.context_processor + def inject_theme_func(): + def get_theme_css(): + all_themes = get_all_themes() + theme_css = all_themes['standard']['cssfile'] + '.css' + try: + misc_preference = Preferences.module('misc') + theme = misc_preference.preference('theme').get() + if theme not in all_themes: + pass + else: + theme_css = all_themes[theme]['cssfile'] + '.css' + except Exception: + # Let the default theme go if exception occurs + pass + + return theme_css + + return { + 'get_theme_css': get_theme_css, + } diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index 4d9aa9155..a9aacb0c9 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -2067,7 +2067,7 @@ define([ } let new_value = _.findWhere(this.field.get('options'), {value: evt.params.data.id}); - if(new_value.preview_src) { + if(new_value && !_.isUndefined(new_value.preview_src) && new_value.preview_src) { this.$el.find('.preview-img img').attr('src', new_value.preview_src); } }, diff --git a/web/pgadmin/static/js/utils.js b/web/pgadmin/static/js/utils.js index 3833cdf3c..5b8dee11f 100644 --- a/web/pgadmin/static/js/utils.js +++ b/web/pgadmin/static/js/utils.js @@ -207,6 +207,7 @@ export function getRandomInt(min, max) { } export function titleize(i_str) { + if(i_str === '' || i_str === null) return i_str; return i_str.split(' ') .map(w => w[0].toUpperCase() + w.substr(1).toLowerCase()) .join(' '); diff --git a/web/pgadmin/static/scss/_backgrid.overrides.scss b/web/pgadmin/static/scss/_backgrid.overrides.scss index c929ddd45..c225c4b02 100644 --- a/web/pgadmin/static/scss/_backgrid.overrides.scss +++ b/web/pgadmin/static/scss/_backgrid.overrides.scss @@ -10,6 +10,14 @@ cursor: pointer; } +.backgrid .ascending .sort-caret { + border-bottom-color: $color-fg; +} + +.backgrid .descending .sort-caret { + border-top-color: $color-fg; +} + .backgrid.backgrid-striped tbody { & tr:nth-child(even) { background: $table-bg; @@ -80,8 +88,8 @@ .backgrid thead td, .backgrid thead th{ - background: $color-bg; - background-color: $color-bg !important; + background: $table-bg; + background-color: $table-bg !important; text-align: left; } @@ -203,7 +211,7 @@ span.form-control:disabled { } .subnode-header { - background-color: $color-bg; + background-color: $header-bg; color: $color-fg; border-bottom: $panel-border; } @@ -290,6 +298,11 @@ table.backgrid { & td.editor { background-color: $color-bg !important; + color: $color-fg !important; + + & input { + color: $color-fg !important; + } } & td.edit-cell.editor:focus { diff --git a/web/pgadmin/static/scss/_pgadmin.style.scss b/web/pgadmin/static/scss/_pgadmin.style.scss index 53aeddf8b..5d51c107e 100644 --- a/web/pgadmin/static/scss/_pgadmin.style.scss +++ b/web/pgadmin/static/scss/_pgadmin.style.scss @@ -186,7 +186,7 @@ &.pg-prop-btn-group-below { text-align: right; padding: $footer-padding; - background: $color-bg; + background: $header-bg; border-top: $panel-border; } } @@ -353,7 +353,7 @@ display: block; text-align: left; cursor: pointer; - background-color: $color-bg; + background-color: $header-bg; padding: 7px; font-size: inherit; border-bottom: $panel-border; @@ -842,7 +842,7 @@ body { } .nav-tabs { - background-color: $color-bg; + background-color: $header-bg; } .editor-toolbar { diff --git a/web/pgadmin/static/scss/_webcabin.pgadmin.scss b/web/pgadmin/static/scss/_webcabin.pgadmin.scss index 91dfb57d2..fca37c979 100644 --- a/web/pgadmin/static/scss/_webcabin.pgadmin.scss +++ b/web/pgadmin/static/scss/_webcabin.pgadmin.scss @@ -24,7 +24,7 @@ .wcFrameTitleBar { height: $title-height; - background-color: $color-bg; + background-color: $header-bg; border-bottom: $panel-border; } @@ -52,7 +52,7 @@ .wcFrameButtonBar { height: $title-height; - background-color: $color-bg; + background-color: inherit; border-bottom: $panel-border; padding: 0rem 0.25rem; @@ -162,7 +162,7 @@ .wcFloating .wcFrameTitleBar { height: $title-height; - background-color: $color-bg; + background-color: $header-bg; border-bottom: $panel-border; } diff --git a/web/pgadmin/static/scss/resources/_default.variables.scss b/web/pgadmin/static/scss/resources/_default.variables.scss index f09b11fb1..29387ddf8 100644 --- a/web/pgadmin/static/scss/resources/_default.variables.scss +++ b/web/pgadmin/static/scss/resources/_default.variables.scss @@ -18,7 +18,7 @@ $color-secondary: $white !default; $color-danger: #e53935 !default; $color-danger-fg: $white !default; $color-danger-light: #F39999 !default; -$color-danger-lighter: #F39999 !default; +$color-danger-lighter: #FAECEC !default; $color-success: #43a047 !default; $color-success-fg: $black !default; @@ -58,6 +58,8 @@ $grid-gutter-width: 15px; $border-radius: 0.25rem; $text-muted: $color-gray-dark !default; +$header-bg: $color-bg !default; + $navbar-bg: $color-primary; $navbar-font-size: 0.925rem; @@ -73,6 +75,8 @@ $navbar-toggler-padding-y: 0.25rem; //no-change $form-group-margin-bottom: 0.5rem; $btn-active-box-shadow: none; +$negative-bg: $color-gray-light !default; + $dropdown-bg: $color-bg; $dropdown-color: $color-fg; $dropdown-link-color: $color-fg; @@ -100,7 +104,7 @@ $card-spacer-y: 0rem; $card-spacer-x: 0rem; $card-border-radius: $border-radius; $card-border-color: $border-color; -$card-cap-bg: $color-bg; +$card-cap-bg: $header-bg; $card-bg: $color-bg; $navbar-padding-y: 0rem; @@ -139,6 +143,11 @@ $input-border-width: $input-btn-border-width; $input-btn-padding-y: .25rem; $input-btn-padding-x: .75rem; +$btn-primary-color: $color-primary-fg; +$btn-success-color: $color-success-fg; +$btn-warning-color: $color-warning-fg; +$btn-danger-color: $color-danger-fg; + $component-active-bg: $color-primary; $input-btn-focus-width: .2rem; $input-btn-focus-color: rgba($component-active-bg, .25); @@ -183,7 +192,7 @@ $splitter-hover-width: 7px; $dropdown-submenu-top: -$dropdown-spacer; -$table-bg: $color-bg; +$table-bg: $color-bg !default; $table-bg-selected: $color-primary-light; $table-hover-border-color: $color-primary; $table-hover-border: $panel-border-width solid $color-primary !important; @@ -205,7 +214,7 @@ $sql-title-bg: #5b6d7c; $sql-title-fg: $white; // Toolbar + editor title heights + title bottom border $sql-editor-panel-top: $title-height + $text-height-calc*16px + $sql-title-padding*2 + $panel-border-width; -$sql-gutters-bg: $color-gray-light; +$sql-gutters-bg: $negative-bg; $sql-history-detail-bg: $color-gray-lighter; $sql-history-success-bg: $color-primary-light; $sql-history-success-fg: $active-color; @@ -224,7 +233,6 @@ $explain-sev-4-bg: #880000 !default; $explain-sev-3-color: #FFFFFF !default; $explain-sev-4-color: #FFFFFF !default; -$negative-bg: $color-gray-light !default; $dialog-box-shadow: 0 0.5rem 3rem $shadow-base-color; $alert-icon-color: $white; @@ -238,6 +246,9 @@ $no-border-radius: 0px !important; $btn-checkbox-padding: $input-btn-padding-y $input-btn-padding-x; +$scrollbar-color: $color-gray !default; +$scrollbar-hover-color: $color-gray-dark !default; + $security-text-color: $white; $security-btn-color: #038bba; diff --git a/web/pgadmin/static/scss/resources/_theme.variables.scss.sample b/web/pgadmin/static/scss/resources/_theme.variables.scss.sample index 30bc06060..b35d53805 100644 --- a/web/pgadmin/static/scss/resources/_theme.variables.scss.sample +++ b/web/pgadmin/static/scss/resources/_theme.variables.scss.sample @@ -49,6 +49,10 @@ $popover-body-color: $color-fg; $active-color: $color-primary; +$header-bg: $color-gray-lighter; + +$table-bg: $color-gray-lighter; + $color-editor-fg: $color-fg; $color-editor-keyword: #908; $color-editor-number: #964; @@ -70,5 +74,9 @@ $explain-sev-4-color: #FFFFFF; $negative-bg: $color-gray-light; +/* Works only with chromium browsers */ +$scrollbar-color: $color-gray-lighter!default; +$scrollbar-hover-color: #666666 !default; + $loader-icon : url("data:image/svg+xml;charset=UTF-8,%3c?xml version='1.0' encoding='utf-8'?%3e%3csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 38 38' style='enable-background:new 0 0 38 38;' xml:space='preserve'%3e%3cstyle type='text/css'%3e .st0%7bfill:none;stroke:%23ebeef3;stroke-width:2;%7d .st1%7bfill:none;stroke:%23326690;stroke-width:2;%7d %3c/style%3e%3cg%3e%3cg transform='translate(1 1)'%3e%3ccircle class='st0' cx='18' cy='18' r='18'/%3e%3cpath class='st1' d='M36,18c0-9.9-8.1-18-18-18 '%3e%3canimateTransform accumulate='none' additive='replace' attributeName='transform' calcMode='linear' dur='0.7s' fill='remove' from='0 18 18' repeatCount='indefinite' restart='always' to='360 18 18' type='rotate'%3e%3c/animateTransform%3e%3c/path%3e%3c/g%3e%3c/g%3e%3c/svg%3e ") !default; $loader-icon-small: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!-- Generator: Adobe Illustrator 23.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 38 38' style='enable-background:new 0 0 38 38;' xml:space='preserve'%3E%3Cstyle type='text/css'%3E .st0%7Bfill:none;stroke:%23EBEEF3;stroke-width:5;%7D .st1%7Bfill:none;stroke:%23222222;stroke-width:5;%7D%0A%3C/style%3E%3Cg%3E%3Cg transform='translate(1 1)'%3E%3Ccircle class='st0' cx='18' cy='18' r='16'/%3E%3Cpath class='st1' d='M34,18c0-8.8-7.2-16-16-16 '%3E%3CanimateTransform accumulate='none' additive='replace' attributeName='transform' calcMode='linear' dur='0.7s' fill='remove' from='0 18 18' repeatCount='indefinite' restart='always' to='360 18 18' type='rotate'%3E%3C/animateTransform%3E%3C/path%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A") !default; diff --git a/web/pgadmin/static/scss/resources/dark/_theme.variables.scss b/web/pgadmin/static/scss/resources/dark/_theme.variables.scss index defd56a9a..d3cb45238 100644 --- a/web/pgadmin/static/scss/resources/dark/_theme.variables.scss +++ b/web/pgadmin/static/scss/resources/dark/_theme.variables.scss @@ -1,45 +1,42 @@ $white: #fff; $black: #000; -$color-bg: #222; +$color-bg: #212121; $color-fg: #ddd; -$color-primary: #40617d; -$color-primary-fg: $white; +$color-primary: #234d6e; +$color-primary-fg: $color-fg; $color-primary-light: #536270; $color-primary-light-fg: $color-primary-fg; $color-primary-dark: #15354f; -$color-secondary: #424242; +$color-secondary: #6b6b6b; -$color-danger: #ff5370; +$color-danger: #da6758; $color-danger-fg: $white; $color-danger-light: #914649; -$color-danger-lighter: #8f8282; +$color-danger-lighter: #212121; -$color-success: #6baa7f; +$color-success: #1a522b; $color-success-fg: $black; $color-success-light: #5a7863; $color-warning: #eea236; $color-warning-fg: $black; -$color-warning-light: #fce5c5; +$color-warning-light: #b18d5a; -/* For dark theme - colors are in reverse order - * gray-dark is lighter then gray-light - */ -$color-gray-dark: #595959; -$color-gray: #424242; +$color-gray-dark: #212121; +$color-gray: #2e2e2e; $color-gray-light: #303030; -$color-gray-lighter: #212121; +$color-gray-lighter: #424242; $color-brand: $white; -$border-color: $color-gray; -$shadow-base-color: $color-gray-lighter; +$border-color: #4a4a4a; +$shadow-base-color: #111111; $text-muted: #9d9fa1; -$input-bg: $color-gray-lighter; +$input-bg: $color-gray-light; $input-color: $color-fg; $input-disabled-bg: $color-bg; @@ -48,16 +45,20 @@ $popover-body-color: $color-fg; $active-color: $color-fg; -$color-editor-fg: #9cdcfe; -$color-editor-keyword: #c58680; -$color-editor-number: #81bb67; -$color-editor-string: #dcdcaa; -$color-editor-variable: #9cdcfe; -$color-editor-variable-2: #9cdcfe; -$color-editor-builtin: #dcdcaa; -$color-editor-comment: #81bb67; -$color-editor-bracket: #d4d4d4; -$color-editor-operator: #d4d4d4; +$header-bg: $color-gray-lighter; + +$table-bg: $color-gray-lighter; + +$color-editor-fg: #7dc9f1; +$color-editor-keyword: #db7c74; +$color-editor-number: #7fcc5c; +$color-editor-string: #e4e487; +$color-editor-variable: #7dc9f1; +$color-editor-variable-2: #7dc9f1; +$color-editor-builtin: #e4e487; +$color-editor-comment: #7fcc5c; +$color-editor-bracket: #d6aaaa; +$color-editor-operator: #d6aaaa; $color-editor-foldmarker: #0000FF !default; $color-editor-activeline: #50B0F0 !default; @@ -69,5 +70,8 @@ $explain-sev-4-color: $color-fg; $negative-bg: $color-bg; +$scrollbar-color: $color-gray-lighter!default; +$scrollbar-hover-color: #666666 !default; + $loader-icon : url("data:image/svg+xml;charset=UTF-8,%3c?xml version='1.0' encoding='utf-8'?%3e%3csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 38 38' style='enable-background:new 0 0 38 38;' xml:space='preserve'%3e%3cstyle type='text/css'%3e .st0%7bfill:none;stroke:%23ebeef3;stroke-width:2;%7d .st1%7bfill:none;stroke:%2340617d;stroke-width:2;%7d %3c/style%3e%3cg%3e%3cg transform='translate(1 1)'%3e%3ccircle class='st0' cx='18' cy='18' r='18'/%3e%3cpath class='st1' d='M36,18c0-9.9-8.1-18-18-18 '%3e%3canimateTransform accumulate='none' additive='replace' attributeName='transform' calcMode='linear' dur='0.7s' fill='remove' from='0 18 18' repeatCount='indefinite' restart='always' to='360 18 18' type='rotate'%3e%3c/animateTransform%3e%3c/path%3e%3c/g%3e%3c/g%3e%3c/svg%3e ") !default; $loader-icon-small: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!-- Generator: Adobe Illustrator 23.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 38 38' style='enable-background:new 0 0 38 38;' xml:space='preserve'%3E%3Cstyle type='text/css'%3E .st0%7Bfill:none;stroke:%23EBEEF3;stroke-width:5;%7D .st1%7Bfill:none;stroke:%2340617d;stroke-width:5;%7D%0A%3C/style%3E%3Cg%3E%3Cg transform='translate(1 1)'%3E%3Ccircle class='st0' cx='18' cy='18' r='16'/%3E%3Cpath class='st1' d='M34,18c0-8.8-7.2-16-16-16 '%3E%3CanimateTransform accumulate='none' additive='replace' attributeName='transform' calcMode='linear' dur='0.7s' fill='remove' from='0 18 18' repeatCount='indefinite' restart='always' to='360 18 18' type='rotate'%3E%3C/animateTransform%3E%3C/path%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A") !default; diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/index.html b/web/pgadmin/tools/datagrid/templates/datagrid/index.html index 30e87c558..9c05e641b 100644 --- a/web/pgadmin/tools/datagrid/templates/datagrid/index.html +++ b/web/pgadmin/tools/datagrid/templates/datagrid/index.html @@ -220,7 +220,7 @@