diff --git a/app/assets/stylesheets/navigation/general.scss b/app/assets/stylesheets/navigation/general.scss index aa079d312..f25eb4ae1 100644 --- a/app/assets/stylesheets/navigation/general.scss +++ b/app/assets/stylesheets/navigation/general.scss @@ -27,7 +27,7 @@ height: var(--top-navigation); position: fixed; width: 100vw; - z-index: 600; + z-index: 610; } .sci--layout-navigation-left { @@ -65,5 +65,6 @@ .sci--layout-content { grid-area: content; padding: 0 1em; + width: calc(100vw - var(--left-navigation) - var(--navigator-navigation)); } } diff --git a/app/assets/stylesheets/navigation/left_menu.scss b/app/assets/stylesheets/navigation/left_menu.scss new file mode 100644 index 000000000..3ed9cccdc --- /dev/null +++ b/app/assets/stylesheets/navigation/left_menu.scss @@ -0,0 +1,37 @@ +// scss-lint:disable SelectorDepth unknownProperties +// scss-lint:disable NestingDepth SelectorFormat + +.sci--layout--left-menu-container { + background-color: $color-white; + box-shadow: $flyout-shadow; + display: flex; + flex-direction: column; + height: 100%; + padding: 1em 0; + width: 100%; + + .sci--layout--menu-item { + align-items: center; + color: $color-black; + cursor: pointer; + display: flex; + flex-direction: column; + height: 60px; + justify-content: center; + text-decoration: none; + width: 100%; + + &[data-active='true'] { + background-color: $color-gainsboro; + box-shadow: inset 4px 0 0 $brand-primary; + } + + &[data-disabled='true'] { + background-color: initial; + box-shadow: none; + cursor: not-allowed; + opacity: .65; + pointer-events: none; + } + } +} diff --git a/app/assets/stylesheets/navigation/top_menu.scss b/app/assets/stylesheets/navigation/top_menu.scss new file mode 100644 index 000000000..faf42a780 --- /dev/null +++ b/app/assets/stylesheets/navigation/top_menu.scss @@ -0,0 +1,64 @@ +// scss-lint:disable SelectorDepth unknownProperties IdSelector +// scss-lint:disable NestingDepth SelectorFormat + +#sciNavigationTopMenuContainer { + display: contents; +} + +.sci--navigation--top-menu-container { + align-items: center; + background-color: $color-white; + box-shadow: $flyout-shadow; + display: flex; + gap: .5em; + height: 100%; + padding: 0 2em; + + .sci--navigation--top-menu-logo { + a { + display: inline-block; + } + + .logo { + max-height: 22px; + + &.small { + display: none; + } + } + } + + .sci--navigation--top-menu-teams { + height: 36px; + margin-left: 2em; + width: 220px; + } + + .sci--navigation--top-menu-search { + margin-left: auto; + margin-right: 1em; + width: 240px; + } + + .sci--navigation--top-menu-user { + align-items: center; + cursor: pointer; + display: flex; + gap: 1em; + margin-left: .75em; + } + + @media(max-width: 1200px) { + .sci--navigation--top-menu-logo { + .logo { + &.large { + display: none; + } + + &.small { + display: initial; + } + } + } + } +} diff --git a/app/controllers/navigations_controller.rb b/app/controllers/navigations_controller.rb new file mode 100644 index 000000000..acff216be --- /dev/null +++ b/app/controllers/navigations_controller.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +class NavigationsController < ApplicationController + include ApplicationHelper + + HELP_MENU_LINKS = [ + { name: I18n.t('left_menu_bar.support_links.support'), url: Constants::SUPPORT_URL }, + { name: I18n.t('left_menu_bar.support_links.tutorials'), url: Constants::TUTORIALS_URL }, + { name: I18n.t('left_menu_bar.academy'), url: Constants::ACADEMY_BL_LINK } + ] + + SETTINGS_MENU_LINKS = [ + { + name: I18n.t('users.settings.sidebar.teams'), + url: Rails.application.routes.url_helpers.teams_path + }, { + name: I18n.t('users.settings.sidebar.account_nav.addons'), + url: Rails.application.routes.url_helpers.addons_path + }, { + name: I18n.t('users.settings.sidebar.webhooks'), + url: Rails.application.routes.url_helpers.users_settings_webhooks_path + } + ] + + USER_MENU_LINKS = [ + { + name: I18n.t('users.settings.sidebar.account_nav.profile'), + url: Rails.application.routes.url_helpers.edit_user_registration_path + }, { + name: I18n.t('users.settings.sidebar.account_nav.preferences'), + url: Rails.application.routes.url_helpers.preferences_path + }, { + name: I18n.t('users.settings.sidebar.account_nav.connected_accounts'), + url: Rails.application.routes.url_helpers.connected_accounts_path + } + ] + + def top_menu + render json: { + root_url: root_path, + logo: logo, + current_team: current_team&.id, + search_url: search_path, + teams: teams, + settings: [], + help_menu: NavigationsController::HELP_MENU_LINKS, + settings_menu: NavigationsController::SETTINGS_MENU_LINKS, + user_menu: NavigationsController::USER_MENU_LINKS, + user: user + } + end + + private + + def logo + { + large_url: image_path('/images/scinote_icon.svg'), + small_url: image_path('/images/sn-icon.svg') + } + end + + def teams + current_user.teams.order(:name).map do |t| + { + label: escape_input(t.name), + value: t.id, + params: { switch_url: switch_users_settings_team_path(t) } + } + end + end + + def user + { + name: escape_input(current_user.full_name), + avatar_url: avatar_path(current_user, :icon_small), + sign_out_url: destroy_user_session_path + } + end +end diff --git a/app/controllers/users/settings/teams_controller.rb b/app/controllers/users/settings/teams_controller.rb index 642d8fe18..7a99f75ac 100644 --- a/app/controllers/users/settings/teams_controller.rb +++ b/app/controllers/users/settings/teams_controller.rb @@ -131,6 +131,18 @@ module Users redirect_to action: :index end + def switch + team = current_user.teams.find_by(id: params[:id]) + + if team && current_user.update(current_team_id: team.id) + flash[:success] = t('users.settings.changed_team_flash', + team: current_user.current_team.name) + render json: { current_team: team.id } + else + render json: { message: t('users.settings.changed_team_error_flash') }, status: :unprocessable_entity + end + end + private def check_create_team_permission diff --git a/app/controllers/users/settings_controller.rb b/app/controllers/users/settings_controller.rb deleted file mode 100644 index ddb455cd5..000000000 --- a/app/controllers/users/settings_controller.rb +++ /dev/null @@ -1,29 +0,0 @@ -module Users - class SettingsController < ApplicationController - before_action :load_user, only: [ - :user_current_team - ] - - def user_current_team - team_id = params[:user][:current_team_id].to_i - if @user.teams_ids.include?(team_id) - @user.current_team_id = team_id - @changed_team = Team.find_by_id(@user.current_team_id) - if @user.save - flash[:success] = t('users.settings.changed_team_flash', - team: @changed_team.name) - redirect_to root_path - return - end - end - flash[:alert] = t('users.settings.changed_team_error_flash') - redirect_back(fallback_location: root_path) - end - - private - - def load_user - @user = current_user - end - end -end diff --git a/app/helpers/left_menu_bar_helper.rb b/app/helpers/left_menu_bar_helper.rb index e4f074077..602f64a66 100644 --- a/app/helpers/left_menu_bar_helper.rb +++ b/app/helpers/left_menu_bar_helper.rb @@ -1,4 +1,41 @@ +# frozen_string_literal: true + module LeftMenuBarHelper + def left_menu_elements + [ + { + url: dashboard_path, + name: t('left_menu_bar.dashboard'), + icon: 'fa-thumbtack', + active: dashboard_are_selected? + }, { + url: projects_path, + name: t('left_menu_bar.projects'), + icon: 'fa-folder', + active: projects_are_selected? + }, { + url: repositories_path, + name: t('left_menu_bar.repositories'), + icon: 'fa-list-alt', + active: repositories_are_selected? + }, { + url: protocols_path, + name: t('left_menu_bar.templates'), + icon: 'fa-edit', + active: templates_are_selected? + }, { + url: reports_path, + name: t('left_menu_bar.reports'), + icon: 'fa-clipboard-check', + active: reports_are_selected? + }, { + url: global_activities_path, + name: t('left_menu_bar.activities'), + icon: 'fa-list', + active: activities_are_selected? + } + ] + end def dashboard_are_selected? controller_name == 'dashboards' diff --git a/app/javascript/packs/vue/navigation/top_menu.js b/app/javascript/packs/vue/navigation/top_menu.js new file mode 100644 index 000000000..1272aa3ff --- /dev/null +++ b/app/javascript/packs/vue/navigation/top_menu.js @@ -0,0 +1,14 @@ + +import Vue from 'vue/dist/vue.esm'; +import TopMenuContainer from '../../../vue/navigation/top_menu.vue'; + +Vue.prototype.i18n = window.I18n; + +window.addEventListener('DOMContentLoaded', () => { + new Vue({ + el: '#sciNavigationTopMenuContainer', + components: { + 'top-menu-container': TopMenuContainer + } + }); +}); diff --git a/app/javascript/vue/navigation/top_menu.vue b/app/javascript/vue/navigation/top_menu.vue new file mode 100644 index 000000000..3e25c0776 --- /dev/null +++ b/app/javascript/vue/navigation/top_menu.vue @@ -0,0 +1,130 @@ + + + diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 3751dde5f..862538288 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -17,6 +17,7 @@ <%= javascript_pack_tag 'application' %> <%= javascript_include_tag 'session_end' %> + <% if MarvinJsService.enabled? && ENV['MARVINJS_API_KEY'] %> @@ -38,6 +39,7 @@ <%= javascript_pack_tag 'tui_image_editor' %> <%= stylesheet_pack_tag 'tui_image_editor_styles' %> + <%= javascript_pack_tag 'vue/navigation/top_menu' %> -
+
<%= render "shared/navigation/top" %>
diff --git a/app/views/shared/navigation/_left.html.erb b/app/views/shared/navigation/_left.html.erb index 621c77e20..11698156e 100644 --- a/app/views/shared/navigation/_left.html.erb +++ b/app/views/shared/navigation/_left.html.erb @@ -1,130 +1,10 @@ -