From bd3fae7009da900520f1343ea596af6929ba653e Mon Sep 17 00:00:00 2001 From: Ilona Podliashanyk Date: Thu, 3 Oct 2024 14:45:51 +0200 Subject: [PATCH 01/10] Configure NPM and add webpack config for building CSS from Sass The essence of this config: Sass files will be compiled into CSS files into the same folder (/static/css/) as it was done in the original implementation (with libsass and setuptools). The resulting files in /static/css will have same layout and names as with the previous solution, except for /static/css/foundation folder. It is dropped completely since it was empty when built with setuptools. This is expected since /sass/foundation folder contains only Sass partials. Named webpack configuration is used in the config. This is to drop the need of having multiple webpack config files per name/target/purpose. --- .gitignore | 4 ++++ package.json | 20 ++++++++++++++++++++ webpack.config.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 package.json create mode 100644 webpack.config.js diff --git a/.gitignore b/.gitignore index 3279c76922..fd82f9731c 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,7 @@ python/nav/web/static/css python/nav/web/static/js/node_modules python/nav/web/static/js/require_config.dev.js python/nav/web/static/js/coverage + +# Javascript libraries +/node_modules +package-lock.json diff --git a/package.json b/package.json new file mode 100644 index 0000000000..6353860a47 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "NAV frontend", + "description": "Network Administration Visualized frontend", + "version": "5", + "private": true, + "dependencies": { + "css-loader": "^6.10.0", + "glob": "^10.3.10", + "mini-css-extract-plugin": "^2.8.0", + "sass": "^1.71.1", + "sass-loader": "^14.1.1", + "webpack": "^5.90.3", + "webpack-cli": "^5.1.4", + "webpack-remove-empty-scripts": "^1.0.4" + }, + "scripts": { + "watch:sass": "webpack --config webpack.config.js --config-name sass --mode development --watch", + "build:sass": "webpack --config webpack.config.js --config-name sass --mode production" + } +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000000..1d15a8c4bf --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,43 @@ +const path = require('path'); +const glob = require('glob'); + +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts'); + +const stylesHandler = MiniCssExtractPlugin.loader; + +module.exports = [ + { + name: 'sass', + entry: { + nav: path.resolve(__dirname, './python/nav/web/sass/nav.scss'), + ...glob.sync(path.resolve(__dirname, './python/nav/web/sass/nav/**.scss')).filter(v => !path.parse(v).name.startsWith('_')).reduce(function (obj, el) { + obj[`nav/${path.parse(el).name}`] = el; + return obj + }, {}), + 'font-awesome/font-awesome': path.resolve(__dirname, './python/nav/web/sass/font-awesome/font-awesome.scss'), + }, + output: { + path: path.join(__dirname, './python/nav/web/static/css'), + clean: true, + }, + plugins: [ + new MiniCssExtractPlugin(), + new RemoveEmptyScriptsPlugin(), + ], + module: { + rules: [ + { + test: /\.s[ac]ss$/i, + use: [stylesHandler, 'css-loader', 'sass-loader'], + }, + { + test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i, + type: 'asset' // webpack will individually pick the best way to include each asset it encounters + }, + ], + }, + // TODO: fix warnings instead of ignoring them + ignoreWarnings: [/./], // Suppress all warnings in the console + }, +]; From c454d2118e1d4caeadb15c4296e92aa1857ddb47 Mon Sep 17 00:00:00 2001 From: Ilona Podliashanyk Date: Thu, 29 Feb 2024 16:52:55 +0100 Subject: [PATCH 02/10] Fix Sass files to get rid of errors during build * Fixes failing assets urls. Read more about problem here https://webpack.js.org/loaders/sass-loader/#problems-with-url. In our case asset urls must be relative to each given entry path (each generated CSS file came from a separate entry). Sass files (entries) have different path depth which introduces another problem - there can't be 1 variable that would satisfy all entries. Furthermore, some assets are defined in the same Sass file AND are used by several entries of varying depth. squash Fix correct asset name and path * Remove redundant imports Otherwise webpack will fail due to assets url not being valid relative to entry path * Fix correct import Otherwise webpack would not build CSS file from entries Also merges duplicate selector definitions into single definition. There were no overlaps in the merged definitions, so no unexpected CSS behaviour would occur. But merging duplicate definitions is better for code maintainability in general. --- python/nav/web/sass/_fonts.scss | 8 ++-- python/nav/web/sass/_navsettings.scss | 7 ++- python/nav/web/sass/nav/_fonts.scss | 8 ++-- python/nav/web/sass/nav/_select2.scss | 1 + python/nav/web/sass/nav/_sensors.scss | 2 - python/nav/web/sass/nav/_settings.scss | 5 ++ python/nav/web/sass/nav/geomap.scss | 26 ++++++----- python/nav/web/sass/nav/info_room.scss | 3 +- python/nav/web/sass/nav/ipdevinfo.scss | 2 +- .../web/sass/nav/jquery-ui-1.8.21.custom.scss | 46 +++++++++---------- python/nav/web/sass/nav/jquery-ui.scss | 34 +++++++------- python/nav/web/sass/nav/multi-select.scss | 4 +- python/nav/web/sass/nav/navlets.scss | 1 - python/nav/web/sass/nav/netmap.scss | 4 +- python/nav/web/sass/nav/networkexplorer.scss | 8 ++-- python/nav/web/sass/nav/openlayers.scss | 3 +- python/nav/web/sass/nav/powersupplies.scss | 12 +++-- 17 files changed, 97 insertions(+), 77 deletions(-) create mode 100644 python/nav/web/sass/nav/_settings.scss diff --git a/python/nav/web/sass/_fonts.scss b/python/nav/web/sass/_fonts.scss index 047453a398..07c8467a57 100644 --- a/python/nav/web/sass/_fonts.scss +++ b/python/nav/web/sass/_fonts.scss @@ -1,18 +1,20 @@ +@import 'navsettings'; + @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url('/static/fonts/OS300.woff') format('woff'); + src: local('Open Sans Light'), local('OpenSans-Light'), url('#{$assets-url}/fonts/OS300.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url('/static/fonts/OS400.woff') format('woff'); + src: local('Open Sans'), local('OpenSans'), url('#{$assets-url}/fonts/OS400.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('/static/fonts/OS600.woff') format('woff'); + src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('#{$assets-url}/fonts/OS600.woff') format('woff'); } \ No newline at end of file diff --git a/python/nav/web/sass/_navsettings.scss b/python/nav/web/sass/_navsettings.scss index 60d767f21c..42de255eb2 100644 --- a/python/nav/web/sass/_navsettings.scss +++ b/python/nav/web/sass/_navsettings.scss @@ -23,8 +23,11 @@ $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (m // Relative image path -$image-path: '../../images' !global; -$image-path-partials: '../images' !global; +// Providing variables for all assets paths in this folder so that there will be no hard coding +$assets-url: '../static' !global; +$image-path: '#{$assets-url}/images' !global; +$image-path-partials: '#{$assets-url}/images' !global; +$fa-font-path: '#{$assets-url}/fonts'; // Width of a row. To create a limited viewport use em-calc // Default from Foundation is $row-width: em-calc(1000) !global; diff --git a/python/nav/web/sass/nav/_fonts.scss b/python/nav/web/sass/nav/_fonts.scss index 1ca0275fc2..030faa0192 100644 --- a/python/nav/web/sass/nav/_fonts.scss +++ b/python/nav/web/sass/nav/_fonts.scss @@ -1,18 +1,20 @@ +@import 'settings'; + @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url('/static/fonts/OS300.woff') format('woff'); + src: local('Open Sans Light'), local('OpenSans-Light'), url('#{$assets-url}/fonts/OS300.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url('/static/fonts/OS400.woff') format('woff'); + src: local('Open Sans'), local('OpenSans'), url('#{$assets-url}/fonts/OS400.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('/static/fonts/OS600.woff') format('woff'); + src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('#{$assets-url}/fonts/OS600.woff') format('woff'); } diff --git a/python/nav/web/sass/nav/_select2.scss b/python/nav/web/sass/nav/_select2.scss index 236d86dcb5..253b63f2b1 100644 --- a/python/nav/web/sass/nav/_select2.scss +++ b/python/nav/web/sass/nav/_select2.scss @@ -2,6 +2,7 @@ Version: 3.4.5 Timestamp: Mon Nov 4 08:22:42 PST 2013 */ @import '../navsettings'; +@import 'settings'; .select2-container { margin: 0 0 1rem 0; diff --git a/python/nav/web/sass/nav/_sensors.scss b/python/nav/web/sass/nav/_sensors.scss index aef207c8d2..426eaa51b0 100644 --- a/python/nav/web/sass/nav/_sensors.scss +++ b/python/nav/web/sass/nav/_sensors.scss @@ -1,5 +1,3 @@ -@import 'navsettings'; - /* * Styles for everything in the environment tab */ diff --git a/python/nav/web/sass/nav/_settings.scss b/python/nav/web/sass/nav/_settings.scss new file mode 100644 index 0000000000..49cc55453d --- /dev/null +++ b/python/nav/web/sass/nav/_settings.scss @@ -0,0 +1,5 @@ +// Assets path variables +// Giving same name to variables as in ../navsettings, and making them default in this folder +$assets-url: '../../static' !default; +$image-path: '#{$assets-url}/images' !default; +$image-path-partials: '#{$assets-url}/images' !default; \ No newline at end of file diff --git a/python/nav/web/sass/nav/geomap.scss b/python/nav/web/sass/nav/geomap.scss index 57f9631aca..0630b0245b 100644 --- a/python/nav/web/sass/nav/geomap.scss +++ b/python/nav/web/sass/nav/geomap.scss @@ -1,3 +1,5 @@ +@import "settings"; + #map { height: 75vh; } @@ -61,51 +63,51 @@ } #time-navigation-prev-jump.enabled:before { - content: url('../../images/geomap/left2.png'); + content: url('#{$assets-url}/images/geomap/left2.png'); } #time-navigation-prev-jump.disabled:before { - content: url('../../images/geomap/left2_grey.png'); + content: url('#{$assets-url}/images/geomap/left2_grey.png'); } #time-navigation-prev.enabled:before { - content: url('../../images/geomap/left1.png'); + content: url('#{$assets-url}/images/geomap/left1.png'); } #time-navigation-prev.disabled:before { - content: url('../../images/geomap/left1_grey.png'); + content: url('#{$assets-url}/images/geomap/left1_grey.png'); } #time-navigation-next.enabled:before { - content: url('../../images/geomap/right1.png'); + content: url('#{$assets-url}/images/geomap/right1.png'); } #time-navigation-next.disabled:before { - content: url('../../images/geomap/right1_grey.png'); + content: url('#{$assets-url}/images/geomap/right1_grey.png'); } #time-navigation-next-jump.enabled:before { - content: url('../../images/geomap/right2.png'); + content: url('#{$assets-url}/images/geomap/right2.png'); } #time-navigation-next-jump.disabled:before { - content: url('../../images/geomap/right2_grey.png'); + content: url('#{$assets-url}/images/geomap/right2_grey.png'); } #time-navigation-last.enabled:before { - content: url('../../images/geomap/right_last.png'); + content: url('#{$assets-url}/images/geomap/right_last.png'); } #time-navigation-last.disabled:before { - content: url('../../images/geomap/right_last_grey.png'); + content: url('#{$assets-url}/images/geomap/right_last_grey.png'); } #time-navigation-up.enabled:before { - content: url('../../images/geomap/up1.png'); + content: url('#{$assets-url}/images/geomap/up1.png'); } #time-navigation-up.disabled:before { - content: url('../../images/geomap/up1_grey.png'); + content: url('#{$assets-url}/images/geomap/up1_grey.png'); } #time-navigation-down.disabled { diff --git a/python/nav/web/sass/nav/info_room.scss b/python/nav/web/sass/nav/info_room.scss index 906bb00c46..d930353ea5 100644 --- a/python/nav/web/sass/nav/info_room.scss +++ b/python/nav/web/sass/nav/info_room.scss @@ -1,4 +1,3 @@ -@import 'sensors'; #netboxes .dataTables_wrapper { display: inline-block; @@ -104,4 +103,4 @@ img.textbottom { padding-top: 0.5rem; padding-bottom: 0.5rem; } -} \ No newline at end of file +} diff --git a/python/nav/web/sass/nav/ipdevinfo.scss b/python/nav/web/sass/nav/ipdevinfo.scss index 2e7b0261f8..66d46ef9ba 100644 --- a/python/nav/web/sass/nav/ipdevinfo.scss +++ b/python/nav/web/sass/nav/ipdevinfo.scss @@ -22,7 +22,7 @@ * */ - @import 'foundation/functions'; + @import '../foundation/functions'; /* Device details table */ diff --git a/python/nav/web/sass/nav/jquery-ui-1.8.21.custom.scss b/python/nav/web/sass/nav/jquery-ui-1.8.21.custom.scss index be376c1053..fdca124a34 100644 --- a/python/nav/web/sass/nav/jquery-ui-1.8.21.custom.scss +++ b/python/nav/web/sass/nav/jquery-ui-1.8.21.custom.scss @@ -8,6 +8,8 @@ * http://docs.jquery.com/UI/Theming/API */ +@import "settings"; + /* Layout helpers ----------------------------------*/ .ui-helper-hidden { display: none; } @@ -28,14 +30,14 @@ ----------------------------------*/ /* states and images */ -.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; width: 16px; height: 16px; background-image: url('#{$assets-url}/images/jqueryui/ui-icons_222222_256x240.png'); } /* Misc visuals ----------------------------------*/ /* Overlays */ -.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: #aaaaaa url('#{$assets-url}/images/jqueryui/ui-bg_flat_0_aaaaaa_40x100.png') 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } /*! @@ -56,26 +58,26 @@ /* .ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; } */ .ui-widget .ui-widget { font-size: 1em; } .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; } -.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url('../../images/jqueryui/ui-bg_flat_75_ffffff_40x100.png') 50% 50% repeat-x; color: #222222; } +.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url('#{$assets-url}/images/jqueryui/ui-bg_flat_75_ffffff_40x100.png') 50% 50% repeat-x; color: #222222; } /*.ui-widget-content a { color: #222222; }*/ -.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url('../../images/jqueryui/ui-bg_highlight-soft_75_cccccc_1x100.png') 50% 50% repeat-x; color: #222222; font-weight: bold; } +.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url('#{$assets-url}/images/jqueryui/ui-bg_highlight-soft_75_cccccc_1x100.png') 50% 50% repeat-x; color: #222222; font-weight: bold; } .ui-widget-header a { color: #222222; } /* Interaction states ----------------------------------*/ -.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url('../../images/jqueryui/ui-bg_glass_75_e6e6e6_1x400.png') 50% 50% repeat-x; font-weight: normal; color: #555555; } +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url('#{$assets-url}/images/jqueryui/ui-bg_glass_75_e6e6e6_1x400.png') 50% 50% repeat-x; font-weight: normal; color: #555555; } .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; } -.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url('../../images/jqueryui/ui-bg_glass_75_dadada_1x400.png') 50% 50% repeat-x; font-weight: normal; color: #212121; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url('#{$assets-url}/images/jqueryui/ui-bg_glass_75_dadada_1x400.png') 50% 50% repeat-x; font-weight: normal; color: #212121; } .ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; } -.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url('../../images/jqueryui/ui-bg_glass_65_ffffff_1x400.png') 50% 50% repeat-x; font-weight: normal; color: #212121; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url('#{$assets-url}/images/jqueryui/ui-bg_glass_65_ffffff_1x400.png') 50% 50% repeat-x; font-weight: normal; color: #212121; } .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; } .ui-widget :active { outline: none; } /* Interaction Cues ----------------------------------*/ -.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url('../../images/jqueryui/ui-bg_glass_55_fbf9ee_1x400.png') 50% 50% repeat-x; color: #363636; } +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url('#{$assets-url}/images/jqueryui/ui-bg_glass_55_fbf9ee_1x400.png') 50% 50% repeat-x; color: #363636; } .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } -.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url('../../images/jqueryui/ui-bg_glass_95_fef1ec_1x400.png') 50% 50% repeat-x; color: #cd0a0a; font-weight: normal;} +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url('#{$assets-url}/images/jqueryui/ui-bg_glass_95_fef1ec_1x400.png') 50% 50% repeat-x; color: #cd0a0a; font-weight: normal;} .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; } .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; } .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } @@ -86,14 +88,13 @@ ----------------------------------*/ /* states and images */ -.ui-icon { width: 16px; height: 16px; background-image: url('../../images/jqueryui/ui-icons_222222_256x240.png'); } -.ui-widget-content .ui-icon {background-image: url('../../images/jqueryui/ui-icons_222222_256x240.png'); } -.ui-widget-header .ui-icon {background-image: url('../../images/jqueryui/ui-icons_222222_256x240.png'); } -.ui-state-default .ui-icon { background-image: url('../../images/jqueryui/ui-icons_888888_256x240.png'); } -.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url('../../images/jqueryui/ui-icons_454545_256x240.png'); } -.ui-state-active .ui-icon {background-image: url('../../images/jqueryui/ui-icons_454545_256x240.png'); } -.ui-state-highlight .ui-icon {background-image: url('../../images/jqueryui/ui-icons_2e83ff_256x240.png'); } -.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url('../../images/jqueryui/ui-icons_cd0a0a_256x240.png'); } +.ui-widget-content .ui-icon {background-image: url('#{$assets-url}/images/jqueryui/ui-icons_222222_256x240.png'); } +.ui-widget-header .ui-icon {background-image: url('#{$assets-url}/images/jqueryui/ui-icons_222222_256x240.png'); } +.ui-state-default .ui-icon { background-image: url('#{$assets-url}/images/jqueryui/ui-icons_888888_256x240.png'); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url('#{$assets-url}/images/jqueryui/ui-icons_454545_256x240.png'); } +.ui-state-active .ui-icon {background-image: url('#{$assets-url}/images/jqueryui/ui-icons_454545_256x240.png'); } +.ui-state-highlight .ui-icon {background-image: url('#{$assets-url}/images/jqueryui/ui-icons_2e83ff_256x240.png'); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url('#{$assets-url}/images/jqueryui/ui-icons_cd0a0a_256x240.png'); } /* positioning */ .ui-icon-carat-1-n { background-position: 0 0; } @@ -283,8 +284,7 @@ .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } /* Overlays */ -.ui-widget-overlay { background: #aaaaaa url('../../images/jqueryui/ui-bg_flat_0_aaaaaa_40x100.png') 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } -.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url('../../images/jqueryui/ui-bg_flat_0_aaaaaa_40x100.png') 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*! +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url('#{$assets-url}/images/jqueryui/ui-bg_flat_0_aaaaaa_40x100.png') 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*! * jQuery UI Resizable 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) @@ -341,7 +341,7 @@ * * http://docs.jquery.com/UI/Autocomplete#theming */ -.ui-autocomplete { position: absolute; cursor: default; } +.ui-autocomplete { position: absolute; cursor: default; } /* workarounds */ * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ @@ -397,8 +397,8 @@ .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ -.ui-button-icons-only { width: 3.4em; } -button.ui-button-icons-only { width: 3.7em; } +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } /*button text element */ .ui-button .ui-button-text { display: block; line-height: 1.4; } @@ -511,7 +511,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } .ui-datepicker select.ui-datepicker-month-year {width: 100%;} -.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-month, .ui-datepicker select.ui-datepicker-year { width: 49%;} .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } diff --git a/python/nav/web/sass/nav/jquery-ui.scss b/python/nav/web/sass/nav/jquery-ui.scss index deee6287a8..8ae81b5dcb 100644 --- a/python/nav/web/sass/nav/jquery-ui.scss +++ b/python/nav/web/sass/nav/jquery-ui.scss @@ -4,6 +4,8 @@ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px * Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ +@import "settings"; + /* Layout helpers ----------------------------------*/ .ui-helper-hidden { @@ -845,7 +847,7 @@ body .ui-tooltip { } .ui-widget-content { border: 1px solid #aaaaaa; - background: #ffffff url("../../images/jqueryui/ui-bg_flat_75_ffffff_40x100.png") 50% 50% repeat-x; + background: #ffffff url("#{$assets-url}/images/jqueryui/ui-bg_flat_75_ffffff_40x100.png") 50% 50% repeat-x; color: #222222; } .ui-widget-content a { @@ -853,7 +855,7 @@ body .ui-tooltip { } .ui-widget-header { border: 1px solid #aaaaaa; - background: #cccccc url("../../images/jqueryui/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x; + background: #cccccc url("#{$assets-url}/images/jqueryui/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x; color: #222222; font-weight: bold; } @@ -867,7 +869,7 @@ body .ui-tooltip { .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; - background: #e6e6e6 url("../../images/jqueryui/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x; + background: #e6e6e6 url("#{$assets-url}/images/jqueryui/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x; font-weight: normal; color: #555555; } @@ -884,7 +886,7 @@ body .ui-tooltip { .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; - background: #dadada url("../../images/jqueryui/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x; + background: #dadada url("#{$assets-url}/images/jqueryui/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x; font-weight: normal; color: #212121; } @@ -903,7 +905,7 @@ body .ui-tooltip { .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; - background: #ffffff url("../../images/jqueryui/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x; + background: #ffffff url("#{$assets-url}/images/jqueryui/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x; font-weight: normal; color: #212121; } @@ -920,7 +922,7 @@ body .ui-tooltip { .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight { border: 1px solid #fcefa1; - background: #fbf9ee url("../../images/jqueryui/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x; + background: #fbf9ee url("#{$assets-url}/images/jqueryui/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x; color: #363636; } .ui-state-highlight a, @@ -932,7 +934,7 @@ body .ui-tooltip { .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error { border: 1px solid #cd0a0a; - background: #fef1ec url("../../images/jqueryui/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x; + background: #fef1ec url("#{$assets-url}/images/jqueryui/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x; color: #cd0a0a; } .ui-state-error a, @@ -978,27 +980,27 @@ body .ui-tooltip { } .ui-icon, .ui-widget-content .ui-icon { - background-image: url("../../images/jqueryui/ui-icons_222222_256x240.png"); + background-image: url("#{$assets-url}/images/jqueryui/ui-icons_222222_256x240.png"); } .ui-widget-header .ui-icon { - background-image: url("../../images/jqueryui/ui-icons_222222_256x240.png"); + background-image: url("#{$assets-url}/images/jqueryui/ui-icons_222222_256x240.png"); } .ui-state-default .ui-icon { - background-image: url("../../images/jqueryui/ui-icons_888888_256x240.png"); + background-image: url("#{$assets-url}/images/jqueryui/ui-icons_888888_256x240.png"); } .ui-state-hover .ui-icon, .ui-state-focus .ui-icon { - background-image: url("../../images/jqueryui/ui-icons_454545_256x240.png"); + background-image: url("#{$assets-url}/images/jqueryui/ui-icons_454545_256x240.png"); } .ui-state-active .ui-icon { - background-image: url("../../images/jqueryui/ui-icons_454545_256x240.png"); + background-image: url("#{$assets-url}/images/jqueryui/ui-icons_454545_256x240.png"); } .ui-state-highlight .ui-icon { - background-image: url("../../images/jqueryui/ui-icons_2e83ff_256x240.png"); + background-image: url("#{$assets-url}/images/jqueryui/ui-icons_2e83ff_256x240.png"); } .ui-state-error .ui-icon, .ui-state-error-text .ui-icon { - background-image: url("../../images/jqueryui/ui-icons_cd0a0a_256x240.png"); + background-image: url("#{$assets-url}/images/jqueryui/ui-icons_cd0a0a_256x240.png"); } /* positioning */ @@ -1211,14 +1213,14 @@ body .ui-tooltip { /* Overlays */ .ui-widget-overlay { - background: #aaaaaa url("../../images/jqueryui/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x; + background: #aaaaaa url("#{$assets-url}/images/jqueryui/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x; opacity: .3; filter: Alpha(Opacity=30); /* support: IE8 */ } .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; - background: #aaaaaa url("../../images/jqueryui/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x; + background: #aaaaaa url("#{$assets-url}/images/jqueryui/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x; opacity: .3; filter: Alpha(Opacity=30); /* support: IE8 */ border-radius: 8px; diff --git a/python/nav/web/sass/nav/multi-select.scss b/python/nav/web/sass/nav/multi-select.scss index ea59711d52..3ef3986cb5 100644 --- a/python/nav/web/sass/nav/multi-select.scss +++ b/python/nav/web/sass/nav/multi-select.scss @@ -1,5 +1,7 @@ +@import "settings"; + .ms-container{ - background: transparent url('../../images/multiselect/switch.png') no-repeat 50% 50%; + background: transparent url('#{$assets-url}/images/multiselect/switch.png') no-repeat 50% 50%; width: 100%; } diff --git a/python/nav/web/sass/nav/navlets.scss b/python/nav/web/sass/nav/navlets.scss index f796ff5797..8fedb56e85 100644 --- a/python/nav/web/sass/nav/navlets.scss +++ b/python/nav/web/sass/nav/navlets.scss @@ -135,7 +135,6 @@ $fullscreen-color: #EEE; .SensorWidget { - @import "sensors"; .room-sensor { display: flex; justify-content: center; diff --git a/python/nav/web/sass/nav/netmap.scss b/python/nav/web/sass/nav/netmap.scss index b9fde88e81..0836cd42b2 100644 --- a/python/nav/web/sass/nav/netmap.scss +++ b/python/nav/web/sass/nav/netmap.scss @@ -1,5 +1,5 @@ -@import '../navsettings'; -$image-path: '../../images'; +@import 'settings'; +$image-path: '#{$assets-url}/images'; #graph-view { background: #ffffff; diff --git a/python/nav/web/sass/nav/networkexplorer.scss b/python/nav/web/sass/nav/networkexplorer.scss index be299b2747..3a387d514a 100644 --- a/python/nav/web/sass/nav/networkexplorer.scss +++ b/python/nav/web/sass/nav/networkexplorer.scss @@ -1,3 +1,5 @@ +@import "settings"; + #working { visibility: hidden; } @@ -13,7 +15,7 @@ } #networktree .node { - background: url('../../images/networkexplorer/vertical.gif') repeat-y top left; + background: url('#{$assets-url}/images/networkexplorer/vertical.gif') repeat-y top left; } #networktree #root { @@ -55,12 +57,12 @@ dl, dl dd { dl, dt, dd { padding-left: 1em; - background-image: url('../../images/networkexplorer/vertical.gif'); + background-image: url('#{$assets-url}/images/networkexplorer/vertical.gif'); background-repeat: repeat-y; } .tree-navigators { - background-image: url('../../images/networkexplorer/vertical.gif'); + background-image: url('#{$assets-url}/images/networkexplorer/vertical.gif'); background-repeat: repeat-y; } #tree > dl, dt, dd { diff --git a/python/nav/web/sass/nav/openlayers.scss b/python/nav/web/sass/nav/openlayers.scss index 3c6fd5d828..5228fa9f80 100644 --- a/python/nav/web/sass/nav/openlayers.scss +++ b/python/nav/web/sass/nav/openlayers.scss @@ -1,4 +1,5 @@ -$ol-imagepath: '../../images/openlayers'; +@import "settings"; +$ol-imagepath: '#{$assets-url}/images/openlayers'; div.olMap { z-index: 0; diff --git a/python/nav/web/sass/nav/powersupplies.scss b/python/nav/web/sass/nav/powersupplies.scss index 22deb01622..73cdce4bf0 100644 --- a/python/nav/web/sass/nav/powersupplies.scss +++ b/python/nav/web/sass/nav/powersupplies.scss @@ -1,3 +1,5 @@ +@import "settings"; + .right { float: right; } .left { float: left; } .text-right { text-align: right; } @@ -8,7 +10,7 @@ h4 { text-align: center; } div.infobox { - margin-bottom: 1em; + margin-bottom: 1em; } div#tablecontainer { @@ -22,7 +24,7 @@ div#errors { /* * Styles for the table - */ + */ table#portadmin-interfacecontainer td { height: 30px; @@ -46,7 +48,7 @@ table#portadmin-interfacecontainer tr td.changed { /* - * Styles for information boxes + * Styles for information boxes */ div.saveinfo { position: absolute; @@ -72,13 +74,13 @@ div#summary ul { .success { color: #4F8A10; background-color: #DFF2BF; - background-image:url('/images/lys/green.png'); + background-image:url('#{$assets-url}/images/lys/green.png'); } .error { color: #D8000C; background-color: #FFBABA; - background-image: url('/images/lys/red.png'); + background-image: url('#{$assets-url}/images/lys/red.png'); } table#powersupplycontainer td.warning { From 3ad9018e8201fa7dee038b7dafcee9b17ade8f50 Mon Sep 17 00:00:00 2001 From: Ilona Podliashanyk Date: Thu, 3 Oct 2024 17:31:24 +0200 Subject: [PATCH 03/10] Add make commands for building css from sass via webpack --- Makefile | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 04c6367cf7..ceebf1e1d7 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: dummy clean distclean testclean docclean doc .FORCE +.PHONY: dummy clean distclean testclean docclean doc cssclean sassbuild sasswatch .FORCE dummy: @echo "'make' is no longer used for deployment. See 'doc/intro/install.rst'" @@ -32,4 +32,17 @@ doc/reference/alerttypes.rst: .FORCE echo "UID=$(shell id -u)" >> .env echo "GID=$(shell id -g)" >> .env +cssclean: + -rm -rf python/nav/web/static/css + +sassbuild: cssclean + @if [ -f package-lock.json ]; then \ + (npm ci && npm run build:sass); \ + else \ + (npm install && npm run build:sass); \ + fi + +sasswatch: + -npm run watch:sass + .FORCE: From 3c372d285b6294d2038cf32f253346c1b21b91c8 Mon Sep 17 00:00:00 2001 From: Ilona Podliashanyk Date: Thu, 3 Oct 2024 17:36:08 +0200 Subject: [PATCH 04/10] Switch to using sassbuild and sasswatch commands in docker --- tools/docker/build.sh | 2 +- tools/docker/sass-watch.sh | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/docker/build.sh b/tools/docker/build.sh index 08c5d19aa7..74cea59df3 100755 --- a/tools/docker/build.sh +++ b/tools/docker/build.sh @@ -9,7 +9,7 @@ fi cd /source pip install -vv -e . -python setup.py build_sass +make sassbuild if [[ ! -f "/etc/nav/nav.conf" ]]; then echo "Copying initial NAV config files into this container" diff --git a/tools/docker/sass-watch.sh b/tools/docker/sass-watch.sh index 4837eccf5e..0639f7bd71 100755 --- a/tools/docker/sass-watch.sh +++ b/tools/docker/sass-watch.sh @@ -2,7 +2,4 @@ # ensures CSS files are rebuilt on SASS file changes # cd /source -while inotifywait -e modify -e move -e create -e delete -r --exclude \# /source/python/nav/web/sass -do - /opt/venvs/nav/bin/python setup.py build_sass -done +make sasswatch From 988707ecea4dc2b2e0bcaddb5cd4518a5e1c2e48 Mon Sep 17 00:00:00 2001 From: Ilona Podliashanyk Date: Tue, 5 Mar 2024 13:10:32 +0100 Subject: [PATCH 05/10] Use sassbuild command in tests Also whitelists make cmd for testing --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 73e1ae57ac..d2f2a5064a 100644 --- a/tox.ini +++ b/tox.ini @@ -64,6 +64,7 @@ allowlist_externals = sed mkdir chmod + make usedevelop = true commands_pre = @@ -73,7 +74,7 @@ commands_pre = commands = unit: pytest -o junit_suite_name="{envname} unit tests" --cov-config {toxinidir}/tests/.coveragerc --cov={toxinidir}/python --cov-report=xml:reports/{envname}/coverage.xml --junitxml=reports/{envname}/unit-results.xml --verbose {posargs:tests/unittests} - {integration,functional}: python setup.py build_sass + {integration,functional}: make sassbuild integration: python -m nav.django.manage check {integration,functional}: nav config install {envdir}/etc From d53016d3086796eb3f90b338db4e10377833774b Mon Sep 17 00:00:00 2001 From: Ilona Podliashanyk Date: Fri, 4 Oct 2024 13:10:12 +0200 Subject: [PATCH 06/10] Remove build_sass from setup.py --- setup.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/setup.py b/setup.py index c6e74831b0..c6b6bc2c1d 100644 --- a/setup.py +++ b/setup.py @@ -1,19 +1,5 @@ -from glob import glob from setuptools import setup -from setuptools.command.build import build - - -# Ensure CSS files are built every time build is invoked -build.sub_commands = [('build_sass', None)] + build.sub_commands - setup( - setup_requires=['libsass', 'setuptools_scm'], - sass_manifests={ - 'nav.web': { - 'sass_path': 'sass', - 'css_path': 'static/css', - 'strip_extension': True, - }, - }, + setup_requires=['setuptools_scm'], ) From a8fb8e0c8f11de5d669e0eaf35aa22979071fe23 Mon Sep 17 00:00:00 2001 From: Ilona Podliashanyk Date: Tue, 5 Mar 2024 13:20:44 +0100 Subject: [PATCH 07/10] Remove libsass dependencies --- pyproject.toml | 2 +- requirements/base.txt | 3 --- tox.ini | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ad3cce68ed..55a6e242c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=61.0", "wheel", "setuptools_scm[toml]>=6.2", "libsass==0.15.1"] +requires = ["setuptools>=61.0", "wheel", "setuptools_scm[toml]>=6.2"] build-backend = "setuptools.build_meta" [project] diff --git a/requirements/base.txt b/requirements/base.txt index 4a10072370..fb46aee4aa 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -32,9 +32,6 @@ iso8601 pynetsnmp-2>=0.1.10 -# libsass for compiling scss files to css using distutils/setuptools -libsass==0.15.1 - napalm==3.4.1 git+https://github.com/Uninett/drf-oidc-auth@v4.0#egg=drf-oidc-auth diff --git a/tox.ini b/tox.ini index d2f2a5064a..276d0d16b3 100644 --- a/tox.ini +++ b/tox.ini @@ -93,7 +93,6 @@ commands = [testenv:javascript] usedevelop=True -deps = libsass==0.15.1 allowlist_externals = xvfb-run commands_pre = commands = From c3b23d13c27563d37200120a377e3e3854075469 Mon Sep 17 00:00:00 2001 From: Ilona Podliashanyk Date: Fri, 8 Nov 2024 11:47:30 +0100 Subject: [PATCH 08/10] Make build system include everything in the static directory Co-authored-by: Morten Brekkevold --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 55a6e242c3..a50ef9bceb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,6 +63,9 @@ include-package-data = true zip-safe = false platforms = ["any"] +[tool.setuptools.package-data] +"nav.web" = ["static/**"] + [tool.setuptools_scm] [tool.setuptools.packages.find] From ecff38526e70ebb4ab9c6a8f9f768d4ec9810376 Mon Sep 17 00:00:00 2001 From: Ilona Podliashanyk Date: Fri, 4 Oct 2024 13:06:57 +0200 Subject: [PATCH 09/10] Update existing docs and add new docs * Updates docs about sass-watcher process in docker * Adds docs about hacking CSS * Adds docs on how to build CSS from Sass when building NAV from source --- doc/hacking/hacking.rst | 19 +++++++++++++++++++ doc/hacking/using-docker.rst | 7 ++++--- doc/howto/generic-install-from-source.rst | 17 +++++++++++++++++ doc/intro/install.rst | 4 ++-- 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/doc/hacking/hacking.rst b/doc/hacking/hacking.rst index b93d84c328..69798f2c91 100644 --- a/doc/hacking/hacking.rst +++ b/doc/hacking/hacking.rst @@ -156,6 +156,7 @@ Directory Description processes. :file:`python/` Python source code. :file:`python/nav/etc/` Example/initial configuration files. +:file:`python/nav/web/sass/` SCSS stylesheets. :file:`python/nav/web/static/` Static media such as CSS stylesheets, images and JavaScript to be served by a webserver. :file:`python/nav/web/templates/` Main/global Django HTML templates. More be located in individual @@ -283,6 +284,24 @@ developing, something browsers love to do! See `config-urlArgs documentation for details. :file:`require_config.dev.js` is listed in the repository :file:`.gitignore` file. +CSS +--- + +NAV uses Sass for styling. If you want to modify the styling, +you can do so by editing the SCSS files in the :file:`python/nav/web/static/scss` +directory. To build the CSS assets, you will need to have Node.js +and npm installed. Once you have these installed, you can run +the following command to build the CSS files:: + + npm install + npm run build:sass + +This will build the CSS assets and place them in the :file:`python/nav/web/static/css` +directory. If you want to watch for changes in the SCSS files and rebuild the +CSS assets automatically, you can run the following command instead:: + + npm run watch:sass + Database diff --git a/doc/hacking/using-docker.rst b/doc/hacking/using-docker.rst index 38bdeb03bc..c6b78958b4 100644 --- a/doc/hacking/using-docker.rst +++ b/doc/hacking/using-docker.rst @@ -187,9 +187,10 @@ nav starts. sass-watcher - This is a process that monitors the :file:`python/nav/web/sass/` subdirectory - for changes, and re-runs ``python setup.py build_sass`` (i.e. rebuilding all - the SASS-based stylesheets) on changes. + This is a process that runs ``npm run watch:sass`` command to monitor and + rebuild all the SASS-based stylesheets whenever changes occur + in the :file:`python/nav/web/sass/` subdirectory. The command continuously + monitors the files and does not exit by itself. The individual logs of these program are typically found inside the ``nav`` container in the :file:`/var/log/supervisor/` directory. The NAV process logs diff --git a/doc/howto/generic-install-from-source.rst b/doc/howto/generic-install-from-source.rst index d3443816fd..9440358fc3 100644 --- a/doc/howto/generic-install-from-source.rst +++ b/doc/howto/generic-install-from-source.rst @@ -5,6 +5,8 @@ This is a generic guide to installing NAV from source code on a \*NIX flavored operating system. The specifics of how to install NAV's dependencies, such as :xref:`PostgreSQL` or :xref:`Graphite` will be entirely up to you and your choice of OS. +Note that building NAV from source will also require Node.js and npm to be installed +in order to manage frontend assets. Dependencies @@ -21,6 +23,11 @@ To build NAV, you need at least the following: * Python >= 3.9.0 * Sphinx >= 1.0 (for building this documentation) +Additionally to build frontend assets (like CSS and JS), you will need: + + * Node.js >= 14.0 + * npm >= 6.0 + Runtime requirements -------------------- @@ -73,6 +80,16 @@ default. Installing NAV ============== +First you need to build the static assets. To do this, you will need to have +Node.js and npm installed. Once you have these installed, you can run +the following command to build the CSS assets:: + + npm install + npm run build:sass + +This will build the CSS assets and place them in the :file:`python/nav/web/static/css` +directory. + To build and install NAV and all its Python dependencies:: pip install -r requirements.txt -c constraints.txt . diff --git a/doc/intro/install.rst b/doc/intro/install.rst index 8cbf854adb..635c2c4120 100644 --- a/doc/intro/install.rst +++ b/doc/intro/install.rst @@ -7,7 +7,8 @@ There are two main options for installing NAV: Either from source code, or from a pre-packaged version. Some of these options will require manually installing and/or configuring 3rd party software that NAV depends on, mainly :xref:`PostgreSQL` -and :xref:`Graphite`. +and :xref:`Graphite`. Building NAV from source code will also require Node.js +and npm to be installed. Installing a pre-packaged version of NAV @@ -96,4 +97,3 @@ For you, we provide two guides: `. 2. :doc:`A step-by-step, detailed guide on installing NAV from source on a Debian GNU/Linux operating system `. - From 19d7c58f18e6d9a0b0459ba583fdde7a34a6f256 Mon Sep 17 00:00:00 2001 From: Ilona Podliashanyk Date: Thu, 7 Nov 2024 13:51:25 +0100 Subject: [PATCH 10/10] Update changelog --- changelog.d/2849.changed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/2849.changed.md diff --git a/changelog.d/2849.changed.md b/changelog.d/2849.changed.md new file mode 100644 index 0000000000..b53bf04e4a --- /dev/null +++ b/changelog.d/2849.changed.md @@ -0,0 +1 @@ +Switched to building CSS from Sass using webpack instead of deprecated `libsass`.