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 @@
-