diff --git a/VERSION b/VERSION index 04a8bc26d..d6f3a382b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.18.6 +1.18.7 diff --git a/app/assets/javascripts/sidebar.js b/app/assets/javascripts/sidebar.js index 9479efd6b..21c726cde 100644 --- a/app/assets/javascripts/sidebar.js +++ b/app/assets/javascripts/sidebar.js @@ -28,6 +28,31 @@ var Sidebar = (function() { } function loadLastState() { + var currentProject = $(SIDEBAR_ID).attr('data-current-project'); + var currentExperiment = $(SIDEBAR_ID).attr('data-current-experiment'); + var currentTask = $(SIDEBAR_ID).attr('data-current-task'); + + if (currentProject) { + let projectBranch = $(`.tree-child[data-branch-id="pro${currentProject}"]`).attr('data-active', 'true'); + projectBranch.prev().addClass('active'); + if (!currentExperiment) projectBranch.closest('.branch').addClass('active'); + } + + if (currentExperiment) { + let experimentBranch = $(`.tree-child[data-branch-id="exp${currentExperiment}"]`).attr('data-active', 'true'); + experimentBranch.prev().addClass('active'); + if (!currentTask) { + experimentBranch.closest('.branch') + .addClass('show-canvas-handler') + .addClass('active'); + } + } + + if (currentTask) { + $(`.leaf[data-module-id="${currentTask}"]`).addClass('active'); + } + + toggleTree($(SIDEBAR_ID).find('.tree-child[data-active="true"]')); toggleTree($(SIDEBAR_ID).find('.tree-child.hidden').filter(sessionStorage.getItem(STORAGE_TREE_KEY))); PerfectSb().update_all(); diff --git a/app/assets/stylesheets/dashboard/calendar.scss b/app/assets/stylesheets/dashboard/calendar.scss index b5bf7d2da..1b91db708 100644 --- a/app/assets/stylesheets/dashboard/calendar.scss +++ b/app/assets/stylesheets/dashboard/calendar.scss @@ -1,7 +1,10 @@ // scss-lint:disable SelectorDepth // scss-lint:disable NestingDepth + + .dashboard-container .calendar-widget { + --calendar-day-size: 32px; grid-column: 10 / span 3; grid-row: 1 / span 6; min-height: 320px; @@ -57,12 +60,12 @@ animation-timing-function: $timing-function-sharp; border-radius: 50%; display: flex; - height: 32px; + height: var(--calendar-day-size); justify-content: center; position: relative; transition: .3s; user-select: none; - width: 32px; + width: var(--calendar-day-size); &.adjacent-month { color: $color-alto; @@ -75,9 +78,9 @@ border-radius: 50%; cursor: pointer; display: flex; - height: 30px; + height: calc(var(--calendar-day-size) - 2px); justify-content: center; - width: 30px; + width: calc(var(--calendar-day-size) - 2px); &:hover { background: $color-concrete; @@ -91,9 +94,9 @@ border-radius: 50%; content: ""; height: 4px; - left: 14px; + left: calc((var(--calendar-day-size) / 2) - 2px); position: absolute; - top: 24px; + top: calc((var(--calendar-day-size) / 2) + 8px); width: 4px; } } @@ -143,3 +146,11 @@ } } } + +@media (max-width: 700px) { + .dashboard-container .calendar-widget { + --calendar-day-size: 28px; + grid-column: 1 / span 12; + grid-row: 2; + } +} diff --git a/app/assets/stylesheets/dashboard/current_tasks.scss b/app/assets/stylesheets/dashboard/current_tasks.scss index d442fefdd..ae83941f0 100644 --- a/app/assets/stylesheets/dashboard/current_tasks.scss +++ b/app/assets/stylesheets/dashboard/current_tasks.scss @@ -335,3 +335,59 @@ } } } + +@media (max-width: 700px) { + .dashboard-container .current-tasks-widget { + --widget-header-size: 72px; + grid-row: 1; + min-height: 450px; + + .widget-title { + flex-basis: 100%; + line-height: 36px; + } + + .actions-container { + flex-grow: 0; + padding: 0; + } + + .current-tasks-navbar { + flex-basis: 0; + flex-grow: 1; + } + + .search-container { + margin-right: 5px; + + .task-search-field { + width: 150px; + + &:focus { + width: 150px; + } + } + } + + .current-tasks-list { + .current-task-item { + .item-row { + flex-wrap: wrap; + + .task-due-date { + @include font-small; + + .fas { + display: none; + } + } + + .task-progress-container { + flex-basis: 100%; + max-width: none; + } + } + } + } + } +} diff --git a/app/assets/stylesheets/dashboard/quick_start.scss b/app/assets/stylesheets/dashboard/quick_start.scss index dd69bc6db..1ab28051a 100644 --- a/app/assets/stylesheets/dashboard/quick_start.scss +++ b/app/assets/stylesheets/dashboard/quick_start.scss @@ -1,3 +1,6 @@ +// scss-lint:disable SelectorDepth +// scss-lint:disable NestingDepth + .dashboard-container .quick-start-widget { grid-column: 1 / span 2; grid-row: 7 / span 6; @@ -34,3 +37,12 @@ grid-row: 5 / span 4; } } + +@media (max-width: 700px) { + .dashboard-container .quick-start-widget { + --widget-header-size: 36px; + grid-column: 1 / span 12; + grid-row: 4; + min-height: 300px; + } +} diff --git a/app/assets/stylesheets/dashboard/recent_work.scss b/app/assets/stylesheets/dashboard/recent_work.scss index 76db9c39e..00fad2df4 100644 --- a/app/assets/stylesheets/dashboard/recent_work.scss +++ b/app/assets/stylesheets/dashboard/recent_work.scss @@ -83,3 +83,41 @@ } } } + +@media (max-width: 700px) { + .dashboard-container .recent-work-widget { + --widget-header-size: 72px; + grid-row: 3; + min-height: 450px; + + .widget-title { + flex-basis: 100%; + line-height: 36px; + } + + .recent-work-container { + .recent-work-item { + flex-wrap: wrap; + margin: 5px 0; + + .object-name { + flex-basis: 100%; + line-height: 18px; + } + + .object-type { + flex-basis: 0; + flex-grow: 1; + line-height: 18px; + } + + .object-changed { + flex-basis: 0; + flex-grow: 1; + line-height: 18px; + text-align: right; + } + } + } + } +} diff --git a/app/assets/stylesheets/dashboard/show.scss b/app/assets/stylesheets/dashboard/show.scss index 12ff213c8..9a9598352 100644 --- a/app/assets/stylesheets/dashboard/show.scss +++ b/app/assets/stylesheets/dashboard/show.scss @@ -1,6 +1,9 @@ +// scss-lint:disable SelectorDepth +// scss-lint:disable NestingDepth + .dashboard-container { - --widget-header-size: 44px; --dashboard-widgets-gap: 30px; + --widget-header-size: 44px; display: grid; grid-column-gap: var(--dashboard-widgets-gap); grid-row-gap: var(--dashboard-widgets-gap); @@ -19,7 +22,6 @@ align-items: center; border-bottom: $border-tertiary; display: flex; - height: var(--widget-header-size); padding-left: 16px; @@ -54,3 +56,18 @@ --dashboard-widgets-gap: 16px; } } + +@media (max-width: 700px) { + .dashboard-container { + --widget-header-size: 72px; + grid-template-rows: auto; + + .widget-header { + flex-wrap: wrap; + + .sci-secondary-navbar { + height: 36px; + } + } + } +} diff --git a/app/assets/stylesheets/forgot_password.scss b/app/assets/stylesheets/forgot_password.scss new file mode 100644 index 000000000..321ba6be5 --- /dev/null +++ b/app/assets/stylesheets/forgot_password.scss @@ -0,0 +1,33 @@ +// scss-lint:disable SelectorDepth NestingDepth IdSelector + +.forgot-password-layout { + #content-wrapper { + margin-left: 0; + + .container:first-child { + padding: 0; + } + } + + .forgot-password-container { + display: flex; + + .forgot-password-form-wrapper { + flex-basis: 50%; + flex-grow: 1; + + .center-block-narrow { + margin-top: 72px; + padding: 0 50px; + } + + .forgot-password-title { + margin-bottom: 24px; + } + + .sci-input-container { + margin-bottom: 24px; + } + } + } +} diff --git a/app/assets/stylesheets/partials/_tree_view.scss b/app/assets/stylesheets/partials/_tree_view.scss index e41a472df..1fb5581dc 100644 --- a/app/assets/stylesheets/partials/_tree_view.scss +++ b/app/assets/stylesheets/partials/_tree_view.scss @@ -58,6 +58,7 @@ .canvas-center-on { animation-timing-function: $timing-function-sharp; color: $color-volcano; + display: none; flex-basis: 36px; flex-shrink: 0; line-height: 50px; @@ -66,6 +67,12 @@ transition: .2s; } + &.active { + .line-wrap { + font-weight: bold; + } + } + &:hover { .line-wrap { background-color: $color-alto; @@ -94,6 +101,12 @@ color: $brand-primary; } } + + &.show-canvas-handler { + .canvas-center-on { + display: inline-block; + } + } } .leaf { diff --git a/app/assets/stylesheets/shared_styles/constants.scss b/app/assets/stylesheets/shared_styles/constants.scss new file mode 100644 index 000000000..7f9e34667 --- /dev/null +++ b/app/assets/stylesheets/shared_styles/constants.scss @@ -0,0 +1 @@ +@import "constants/*"; diff --git a/app/assets/stylesheets/shared_styles/elements/input_fields.scss b/app/assets/stylesheets/shared_styles/elements/input_fields.scss index 368883d14..12f121c36 100644 --- a/app/assets/stylesheets/shared_styles/elements/input_fields.scss +++ b/app/assets/stylesheets/shared_styles/elements/input_fields.scss @@ -3,6 +3,7 @@ .sci-input-container { display: inline-block; position: relative; + width: 100%; label { @include font-small; @@ -14,8 +15,8 @@ .sci-input-field { @include font-button; animation-timing-function: $timing-function-sharp; - border: $border-default; - border-radius: $border-radius-default; + border: $border-secondary; + border-radius: $border-radius-default !important; box-shadow: none; height: 36px; outline: 0; diff --git a/app/assets/stylesheets/shared_styles/elements/navigation.scss b/app/assets/stylesheets/shared_styles/elements/navigation.scss index bc2c5442a..c8b9575b7 100644 --- a/app/assets/stylesheets/shared_styles/elements/navigation.scss +++ b/app/assets/stylesheets/shared_styles/elements/navigation.scss @@ -1,6 +1,7 @@ .sci-secondary-navbar { display: flex; height: 100%; + overflow-x: auto; .navbar-link { @include font-small; @@ -13,6 +14,7 @@ position: relative; text-decoration: none; text-transform: uppercase; + white-space: nowrap; &:hover { color: $color-volcano; diff --git a/app/assets/stylesheets/sign_up.scss b/app/assets/stylesheets/sign_up.scss new file mode 100644 index 000000000..385f93697 --- /dev/null +++ b/app/assets/stylesheets/sign_up.scss @@ -0,0 +1,61 @@ +// scss-lint:disable SelectorDepth NestingDepth IdSelector + +.sign-up-layout { + #content-wrapper { + margin-left: 0; + + .container:first-child { + padding: 0; + } + } + + .sign-up-container { + display: flex; + + .sign-up-form-wrapper { + flex-basis: 50%; + flex-grow: 1; + + .center-block-narrow { + margin-top: 72px; + padding: 0 50px; + } + + .sign-up-title { + margin-bottom: 24px; + } + + .sci-input-container { + margin-bottom: 24px; + + .minimum-password-length { + @include font-small; + } + } + + .sign-up-button { + padding: 7px 32px; + } + + .linkedin-container { + margin-bottom: 24px; + + .linkedin-link { + margin-right: 15px; + + &:hover { + text-decoration: none; + } + } + + .linkedin-signin-button { + margin: 0; + } + + span { + font-weight: bold; + } + } + } + } +} diff --git a/app/assets/stylesheets/sing_in.scss b/app/assets/stylesheets/sing_in.scss new file mode 100644 index 000000000..d6f2b5576 --- /dev/null +++ b/app/assets/stylesheets/sing_in.scss @@ -0,0 +1,73 @@ +// scss-lint:disable SelectorDepth NestingDepth IdSelector + +.sign-in-layout { + #content-wrapper { + margin-left: 0; + + .container:first-child { + padding: 0; + } + } + + .sign-in-container { + display: flex; + + .sign-in-form-wrapper { + flex-basis: 50%; + flex-grow: 1; + + .center-block-narrow { + margin-top: 72px; + padding: 0 50px; + } + + .log-in-title { + margin-bottom: 24px; + } + + .remember-me { + align-items: center; + display: flex; + margin-bottom: 24px; + + label { + margin-left: 8px; + margin-bottom: 0; + } + } + + .sci-input-container { + margin-bottom: 24px; + } + + .linkedin-container { + margin-bottom: 24px; + + .linkedin-link { + margin-right: 15px; + + &:hover { + text-decoration: none; + } + } + + .linkedin-signin-button { + margin: 0; + } + + span { + font-weight: bold; + } + } + + .log-in-button { + padding: 7px 32px; + } + + .forgot-password-link { + display: inline-block; + margin-bottom: 16px; + } + } + } +} diff --git a/app/controllers/api/v1/inventory_columns_controller.rb b/app/controllers/api/v1/inventory_columns_controller.rb index 8be48c93d..600a040db 100644 --- a/app/controllers/api/v1/inventory_columns_controller.rb +++ b/app/controllers/api/v1/inventory_columns_controller.rb @@ -56,9 +56,7 @@ module Api private def check_manage_permissions - unless can_manage_repository_column?(@inventory_column) - raise PermissionError.new(RepositoryColumn, :manage) - end + raise PermissionError.new(RepositoryColumn, :manage) unless can_manage_repository_column?(@inventory_column) end def check_create_permissions @@ -66,12 +64,11 @@ module Api end def inventory_column_params - unless params.require(:data).require(:type) == 'inventory_columns' - raise TypeError - end + raise TypeError unless params.require(:data).require(:type) == 'inventory_columns' + params.require(:data).require(:attributes) new_params = params - .permit(data: { attributes: %i(name data_type) })[:data] + .permit(data: { attributes: [:name, :data_type, metadata: {}] })[:data] .merge(created_by: @current_user) if new_params[:attributes][:data_type].present? new_params[:attributes][:data_type] = @@ -82,9 +79,8 @@ module Api end def update_inventory_column_params - unless params.require(:data).require(:id).to_i == params[:id].to_i - raise IDMismatchError - end + raise IDMismatchError unless params.require(:data).require(:id).to_i == params[:id].to_i + if inventory_column_params[:attributes].include?(:data_type) raise ActiveRecord::RecordInvalid, I18n.t('api.core.errors.inventory_column_type.detail') diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index 13fcbd415..b779d6118 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -28,25 +28,40 @@ module Users email = auth.info.email email ||= auth.dig(:extra, :raw_info, :id_token_claims, :emails)&.first user = User.from_omniauth(auth) - if user - # User found in database so just sign in him - sign_in_and_redirect(user) - elsif email.present? - user = User.find_by(email: email) - if user.blank? - # Create new user and identity - User.create_from_omniauth!(auth) - sign_in_and_redirect(user) - elsif provider_conf[:auto_link_on_sign_in] - # Link to existing local account + # User found in database so just signing in + return sign_in_and_redirect(user) if user.present? + + if email.blank? + # No email in the token so can not link or create user + error_message = I18n.t('devise.azure.errors.no_email') + return redirect_to after_omniauth_failure_path_for(resource_name) + end + + user = User.find_by(email: email) + + if user.blank? + # Create new user and identity + full_name = "#{auth.info.first_name} #{auth.info.last_name}" + user = User.new(full_name: full_name, + initials: generate_initials(full_name), + email: email, + password: generate_user_password) + User.transaction do + user.save! user.user_identities.create!(provider: auth.provider, uid: auth.uid) - sign_in_and_redirect(user) - else - # Cannot do anything with it, so just return an error - error_message = I18n.t('devise.azure.errors.no_local_user_map') - redirect_to after_omniauth_failure_path_for(resource_name) + user.update!(confirmed_at: user.created_at) end + + sign_in_and_redirect(user) + elsif provider_conf[:auto_link_on_sign_in] + # Link to existing local account + user.user_identities.create!(provider: auth.provider, uid: auth.uid) + sign_in_and_redirect(user) + else + # Cannot do anything with it, so just return an error + error_message = I18n.t('devise.azure.errors.no_local_user_map') + redirect_to after_omniauth_failure_path_for(resource_name) end rescue StandardError => e Rails.logger.error e.message diff --git a/app/helpers/form_tag_helper.rb b/app/helpers/form_tag_helper.rb index 0d16834cf..7fd67bf08 100644 --- a/app/helpers/form_tag_helper.rb +++ b/app/helpers/form_tag_helper.rb @@ -1,9 +1,10 @@ module FormTagHelper def recaptcha_input_tag if Rails.configuration.x.enable_recaptcha - res = "