From 7376b363a87d6e898dfdecc970dc7c9c873ae94d Mon Sep 17 00:00:00 2001 From: Martin Artnik <85488244+artoscinote@users.noreply.github.com> Date: Tue, 17 Oct 2023 11:36:08 +0200 Subject: [PATCH 001/128] Asset sync model and endpoints [SCI-9465] (#6399) --- app/controllers/asset_sync_controller.rb | 43 +++++++++++++++++++ app/models/asset.rb | 1 + app/models/asset_sync_token.rb | 33 ++++++++++++++ app/models/user.rb | 1 + .../asset_sync_token_serializer.rb | 19 ++++++++ config/initializers/constants.rb | 2 + config/routes.rb | 3 ++ ...20231006141428_create_asset_sync_tokens.rb | 15 +++++++ db/schema.rb | 17 +++++++- 9 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 app/controllers/asset_sync_controller.rb create mode 100644 app/models/asset_sync_token.rb create mode 100644 app/serializers/asset_sync_token_serializer.rb create mode 100644 db/migrate/20231006141428_create_asset_sync_tokens.rb diff --git a/app/controllers/asset_sync_controller.rb b/app/controllers/asset_sync_controller.rb new file mode 100644 index 000000000..75b9a7ad9 --- /dev/null +++ b/app/controllers/asset_sync_controller.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +class AssetSyncController < ApplicationController + skip_before_action :authenticate_user!, only: :update + skip_before_action :verify_authenticity_token, only: :update + before_action :authenticate_asset_sync_token!, only: :update + + def show + asset = Asset.find_by(params[:asset_id]) + + head :forbidden unless asset && can_manage_asset?(asset) + + asset_sync_token = current_user.asset_sync_tokens.find_or_create_by(asset_id: params[:asset_id]) + + unless asset_sync_token.token_valid? + asset_sync_token = current_user.asset_sync_tokens.create(asset_id: params[:asset_id]) + end + + render json: AssetSyncTokenSerializer.new(asset_sync_token).as_json + end + + def update + head(:conflict) and return if @asset_sync_token.conflicts?(request.headers['VersionToken']) + + @asset.file.attach(io: request.body, filename: @asset.file.filename) + @asset.touch + + render json: AssetSyncTokenSerializer.new(@asset_sync_token).as_json + end + + # private + + def authenticate_asset_sync_token! + @asset_sync_token = AssetSyncToken.find_by(token: request.headers['Authentication']) + + head(:unauthorized) and return unless @asset_sync_token&.token_valid? + + @asset = @asset_sync_token.asset + @current_user = @asset_sync_token.user + + head :forbidden unless can_manage_asset?(@asset) + end +end diff --git a/app/models/asset.rb b/app/models/asset.rb index 64a9e1235..928710fd2 100644 --- a/app/models/asset.rb +++ b/app/models/asset.rb @@ -44,6 +44,7 @@ class Asset < ApplicationRecord dependent: :nullify has_many :report_elements, inverse_of: :asset, dependent: :destroy has_one :asset_text_datum, inverse_of: :asset, dependent: :destroy + has_many :asset_sync_tokens, dependent: :destroy scope :sort_assets, lambda { |sort_value = 'new'| sort = case sort_value diff --git a/app/models/asset_sync_token.rb b/app/models/asset_sync_token.rb new file mode 100644 index 000000000..8c1224366 --- /dev/null +++ b/app/models/asset_sync_token.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +class AssetSyncToken < ApplicationRecord + belongs_to :user + belongs_to :asset + + after_initialize :generate_token + after_initialize :set_default_expiration + + validates :token, uniqueness: true, presence: true + + def version_token + asset.updated_at.to_i.to_s + end + + def token_valid? + !revoked_at? && expires_at > Time.current + end + + def conflicts?(token) + version_token != token + end + + private + + def generate_token + self.token ||= SecureRandom.urlsafe_base64(32) + end + + def set_default_expiration + self.expires_at ||= Constants::ASSET_SYNC_TOKEN_EXPIRATION.from_now + end +end diff --git a/app/models/user.rb b/app/models/user.rb index d659da492..3458807e2 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -318,6 +318,7 @@ class User < ApplicationRecord has_many :access_tokens, class_name: 'Doorkeeper::AccessToken', foreign_key: :resource_owner_id, dependent: :delete_all + has_many :asset_sync_tokens, dependent: :destroy has_many :hidden_repository_cell_reminders, dependent: :destroy diff --git a/app/serializers/asset_sync_token_serializer.rb b/app/serializers/asset_sync_token_serializer.rb new file mode 100644 index 000000000..cccf23a36 --- /dev/null +++ b/app/serializers/asset_sync_token_serializer.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class AssetSyncTokenSerializer < ActiveModel::Serializer + include Rails.application.routes.url_helpers + + attributes :url, :asset_id, :filename, :token, :asset_id, :version_token, :checksum + + def checksum + object.asset.file.checksum + end + + def url + object.asset.file.url + end + + def filename + object.asset.file.filename + end +end diff --git a/config/initializers/constants.rb b/config/initializers/constants.rb index b1b035f19..246b48430 100644 --- a/config/initializers/constants.rb +++ b/config/initializers/constants.rb @@ -416,6 +416,8 @@ class Constants FAST_STATUS_POLLING_INTERVAL = 5000 SLOW_STATUS_POLLING_INTERVAL = 10000 + ASSET_SYNC_TOKEN_EXPIRATION = 1.year + # ) \ / ( # /|\ )\_/( /|\ # * / | \ (/\|/\) / | \ * diff --git a/config/routes.rb b/config/routes.rb index 0aec0fcc9..d97a6e320 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1002,6 +1002,9 @@ Rails.application.routes.draw do end end + get 'asset_sync/:asset_id', to: 'asset_sync#show' + put 'asset_sync', to: 'asset_sync#update' + post 'global_activities', to: 'global_activities#index' constraints WopiSubdomain do diff --git a/db/migrate/20231006141428_create_asset_sync_tokens.rb b/db/migrate/20231006141428_create_asset_sync_tokens.rb new file mode 100644 index 000000000..f9734cd81 --- /dev/null +++ b/db/migrate/20231006141428_create_asset_sync_tokens.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class CreateAssetSyncTokens < ActiveRecord::Migration[7.0] + def change + create_table :asset_sync_tokens do |t| + t.references :user, null: false, foreign_key: true + t.references :asset, null: false, foreign_key: true + t.string :token, index: { unique: true } + t.timestamp :expires_at + t.timestamp :revoked_at + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 184a209eb..eac28b41c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_10_03_114337) do +ActiveRecord::Schema[7.0].define(version: 2023_10_06_141428) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gist" enable_extension "pg_trgm" @@ -76,6 +76,19 @@ ActiveRecord::Schema[7.0].define(version: 2023_10_03_114337) do t.datetime "updated_at", null: false end + create_table "asset_sync_tokens", force: :cascade do |t| + t.bigint "user_id", null: false + t.bigint "asset_id", null: false + t.string "token" + t.datetime "expires_at", precision: nil + t.datetime "revoked_at", precision: nil + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["asset_id"], name: "index_asset_sync_tokens_on_asset_id" + t.index ["token"], name: "index_asset_sync_tokens_on_token", unique: true + t.index ["user_id"], name: "index_asset_sync_tokens_on_user_id" + end + create_table "asset_text_data", force: :cascade do |t| t.text "data", null: false t.bigint "asset_id", null: false @@ -1309,6 +1322,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_10_03_114337) do add_foreign_key "activities", "my_modules" add_foreign_key "activities", "projects" add_foreign_key "activities", "users", column: "owner_id" + add_foreign_key "asset_sync_tokens", "assets" + add_foreign_key "asset_sync_tokens", "users" add_foreign_key "asset_text_data", "assets" add_foreign_key "assets", "users", column: "created_by_id" add_foreign_key "assets", "users", column: "last_modified_by_id" From 20312862614cd8c7e057f8f903b7e4f0920e094c Mon Sep 17 00:00:00 2001 From: Ivan Kljun Date: Thu, 19 Oct 2023 11:53:18 +0200 Subject: [PATCH 002/128] Implement file-checkout localhost call [SCI-9466] --- .../javascripts/sitewide/constants.js.erb | 1 + app/controllers/asset_sync_controller.rb | 2 +- .../shared/content/attachments/context_menu.vue | 17 +++++++++++++++++ app/serializers/asset_serializer.rb | 3 ++- config/initializers/constants.rb | 1 + config/initializers/extends.rb | 2 ++ config/locales/en.yml | 1 + config/routes.rb | 2 +- 8 files changed, 26 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/sitewide/constants.js.erb b/app/assets/javascripts/sitewide/constants.js.erb index 7f473c423..8e37b3abc 100644 --- a/app/assets/javascripts/sitewide/constants.js.erb +++ b/app/assets/javascripts/sitewide/constants.js.erb @@ -14,4 +14,5 @@ const GLOBAL_CONSTANTS = { FILENAME_MAX_LENGTH: <%= Constants::FILENAME_MAX_LENGTH %>, FAST_STATUS_POLLING_INTERVAL: <%= Constants::FAST_STATUS_POLLING_INTERVAL %>, SLOW_STATUS_POLLING_INTERVAL: <%= Constants::SLOW_STATUS_POLLING_INTERVAL %>, + ASSET_SYNC_URL: '<%= Constants::ASSET_SYNC_URL %>', }; diff --git a/app/controllers/asset_sync_controller.rb b/app/controllers/asset_sync_controller.rb index 75b9a7ad9..c271fc518 100644 --- a/app/controllers/asset_sync_controller.rb +++ b/app/controllers/asset_sync_controller.rb @@ -6,7 +6,7 @@ class AssetSyncController < ApplicationController before_action :authenticate_asset_sync_token!, only: :update def show - asset = Asset.find_by(params[:asset_id]) + asset = Asset.find_by(id: params[:asset_id]) head :forbidden unless asset && can_manage_asset?(asset) diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index 768093634..fe10d58b8 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -30,6 +30,7 @@ @open_ove_editor="openOVEditor(attachment.attributes.urls.open_vector_editor_edit)" @open_marvinjs_editor="openMarvinJsEditor" @open_scinote_editor="openScinoteEditor" + @open_locally="openLocally" @delete="deleteModal = true" @viewMode="changeViewMode" @move="showMoveModal" @@ -52,6 +53,7 @@ import moveAssetModal from '../modal/move.vue' import MoveMixin from './mixins/move.js' import MenuDropdown from '../../menu_dropdown.vue' + import axios from '../../../../packs/custom_axios' export default { name: 'contextMenu', @@ -100,6 +102,10 @@ emit: 'open_scinote_editor', }) } + menu.push({ + text: this.i18n.t('Open_locally'), + emit: 'open_locally' + }) menu.push({ text: this.i18n.t('Download'), url: this.attachment.attributes.urls.download, @@ -132,6 +138,17 @@ } }, methods: { + async openLocally() { + try { + const response = await axios.get(this.attachment.attributes.urls.open_locally); + const data = response.data; + const syncUrl = GLOBAL_CONSTANTS.ASSET_SYNC_URL; + await axios.post(syncUrl, data); + } catch (error) { + console.error("Error in request:", error); + } + }, + // TODO: add method to handle get to SciNote and then post to local URL changeViewMode(viewMode) { this.$emit('attachment:viewMode', viewMode) $.ajax({ diff --git a/app/serializers/asset_serializer.rb b/app/serializers/asset_serializer.rb index 810f1d5fc..0b344a64a 100644 --- a/app/serializers/asset_serializer.rb +++ b/app/serializers/asset_serializer.rb @@ -131,7 +131,8 @@ class AssetSerializer < ActiveModel::Serializer start_edit_image: start_edit_image_path(object), delete: asset_destroy_path(object), move_targets: asset_move_tagets_path(object), - move: asset_move_path(object) + move: asset_move_path(object), + open_locally: asset_sync_show_path(object) ) end urls[:open_vector_editor_edit] = edit_gene_sequence_asset_path(object.id) if can_manage_asset?(user, object) diff --git a/config/initializers/constants.rb b/config/initializers/constants.rb index 246b48430..94fc56bc5 100644 --- a/config/initializers/constants.rb +++ b/config/initializers/constants.rb @@ -417,6 +417,7 @@ class Constants SLOW_STATUS_POLLING_INTERVAL = 10000 ASSET_SYNC_TOKEN_EXPIRATION = 1.year + ASSET_SYNC_URL = ENV['ASSET_SYNC_URL'].freeze # ) \ / ( # /|\ )\_/( /|\ diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb index adce2e064..f4719ef2e 100644 --- a/config/initializers/extends.rb +++ b/config/initializers/extends.rb @@ -610,6 +610,8 @@ class Extends www.gstatic.com/recaptcha/ ) + EXTERNAL_SERVICES << Constants::ASSET_SYNC_URL unless EXTERNAL_SERVICES.include?(Constants::ASSET_SYNC_URL) + COLORED_BACKGROUND_ACTIONS = %w( my_modules/protocols my_modules/signatures diff --git a/config/locales/en.yml b/config/locales/en.yml index f62736425..9b1ae3f34 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3858,6 +3858,7 @@ en: Add: "Add" Asset: "File" Assets: "Files" + Open_locally: "Open locally" Download: "Download" Edit: "Edit" Save: "Save" diff --git a/config/routes.rb b/config/routes.rb index d97a6e320..1d61ab2db 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1002,7 +1002,7 @@ Rails.application.routes.draw do end end - get 'asset_sync/:asset_id', to: 'asset_sync#show' + get 'asset_sync/:asset_id', to: 'asset_sync#show', as: :asset_sync_show put 'asset_sync', to: 'asset_sync#update' post 'global_activities', to: 'global_activities#index' From d181465e121f11c5e21801adba8d2c7fc67452c6 Mon Sep 17 00:00:00 2001 From: Martin Artnik Date: Tue, 24 Oct 2023 13:51:25 +0200 Subject: [PATCH 003/128] Fix initialization and add download endpoint [SCI-9465] --- app/controllers/asset_sync_controller.rb | 10 +++++++--- app/serializers/asset_sync_token_serializer.rb | 2 +- config/initializers/extends.rb | 4 +++- config/routes.rb | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/controllers/asset_sync_controller.rb b/app/controllers/asset_sync_controller.rb index c271fc518..00b51ef30 100644 --- a/app/controllers/asset_sync_controller.rb +++ b/app/controllers/asset_sync_controller.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true class AssetSyncController < ApplicationController - skip_before_action :authenticate_user!, only: :update - skip_before_action :verify_authenticity_token, only: :update - before_action :authenticate_asset_sync_token!, only: :update + skip_before_action :authenticate_user!, only: %i(update download) + skip_before_action :verify_authenticity_token, only: %i(update download) + before_action :authenticate_asset_sync_token!, only: %i(update download) def show asset = Asset.find_by(id: params[:asset_id]) @@ -19,6 +19,10 @@ class AssetSyncController < ApplicationController render json: AssetSyncTokenSerializer.new(asset_sync_token).as_json end + def download + redirect_to @asset.file.url + end + def update head(:conflict) and return if @asset_sync_token.conflicts?(request.headers['VersionToken']) diff --git a/app/serializers/asset_sync_token_serializer.rb b/app/serializers/asset_sync_token_serializer.rb index cccf23a36..87ded4ad6 100644 --- a/app/serializers/asset_sync_token_serializer.rb +++ b/app/serializers/asset_sync_token_serializer.rb @@ -10,7 +10,7 @@ class AssetSyncTokenSerializer < ActiveModel::Serializer end def url - object.asset.file.url + asset_sync_download_url(asset_id: object.asset) end def filename diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb index f4719ef2e..73cd9b033 100644 --- a/config/initializers/extends.rb +++ b/config/initializers/extends.rb @@ -610,7 +610,9 @@ class Extends www.gstatic.com/recaptcha/ ) - EXTERNAL_SERVICES << Constants::ASSET_SYNC_URL unless EXTERNAL_SERVICES.include?(Constants::ASSET_SYNC_URL) + if Constants::ASSET_SYNC_URL && EXTERNAL_SERVICES.exclude?(Constants::ASSET_SYNC_URL) + EXTERNAL_SERVICES << Constants::ASSET_SYNC_URL + end COLORED_BACKGROUND_ACTIONS = %w( my_modules/protocols diff --git a/config/routes.rb b/config/routes.rb index 1d61ab2db..82b899f8a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1003,6 +1003,7 @@ Rails.application.routes.draw do end get 'asset_sync/:asset_id', to: 'asset_sync#show', as: :asset_sync_show + get 'asset_sync/:asset_id/download', to: 'asset_sync#download', as: :asset_sync_download put 'asset_sync', to: 'asset_sync#update' post 'global_activities', to: 'global_activities#index' From 22a130e5025f558a81aee454ee9cacc326b3bcbe Mon Sep 17 00:00:00 2001 From: Martin Artnik Date: Wed, 25 Oct 2023 09:27:27 +0200 Subject: [PATCH 004/128] Fix download endpoint to allow redirects to other hosts [SCI-9465] --- app/controllers/asset_sync_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/asset_sync_controller.rb b/app/controllers/asset_sync_controller.rb index 00b51ef30..1eff86d04 100644 --- a/app/controllers/asset_sync_controller.rb +++ b/app/controllers/asset_sync_controller.rb @@ -20,7 +20,7 @@ class AssetSyncController < ApplicationController end def download - redirect_to @asset.file.url + redirect_to(@asset.file.url, allow_other_host: true) end def update From f015c8c56e8487dc7b6641c8d82c01afa2243f2b Mon Sep 17 00:00:00 2001 From: Martin Artnik Date: Fri, 3 Nov 2023 09:46:05 +0100 Subject: [PATCH 005/128] Create a copy of the synced file in case of conflict [SCI-9640] --- app/controllers/asset_sync_controller.rb | 28 +++++++++++++++++++++++- app/models/asset.rb | 4 ++++ config/locales/en.yml | 1 + 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/controllers/asset_sync_controller.rb b/app/controllers/asset_sync_controller.rb index 1eff86d04..5cf619ccc 100644 --- a/app/controllers/asset_sync_controller.rb +++ b/app/controllers/asset_sync_controller.rb @@ -24,7 +24,13 @@ class AssetSyncController < ApplicationController end def update - head(:conflict) and return if @asset_sync_token.conflicts?(request.headers['VersionToken']) + if @asset_sync_token.conflicts?(request.headers['VersionToken']) + render( + json: AssetSyncTokenSerializer.new(conflicting_asset_copy_token).as_json, + status: :conflict + ) + return + end @asset.file.attach(io: request.body, filename: @asset.file.filename) @asset.touch @@ -34,6 +40,26 @@ class AssetSyncController < ApplicationController # private + def conflicting_asset_copy_token + Asset.transaction do + new_asset = @asset.dup + new_asset.save + new_asset.file.attach( + io: request.body, + filename: "#{@asset.file.filename.base} (#{t('general.copy')}).#{@asset.file.filename.extension}" + ) + + case @asset.parent + when Step + StepAsset.create!(step: @asset.step, asset: new_asset) + when Result + ResultAsset.create!(result: @asset.result, asset: new_asset) + end + + current_user.asset_sync_tokens.create!(asset_id: new_asset.id) + end + end + def authenticate_asset_sync_token! @asset_sync_token = AssetSyncToken.find_by(token: request.headers['Authentication']) diff --git a/app/models/asset.rb b/app/models/asset.rb index 1429f6a11..1c6387828 100644 --- a/app/models/asset.rb +++ b/app/models/asset.rb @@ -466,6 +466,10 @@ class Asset < ApplicationRecord (result || step)&.my_module end + def parent + step || result || repository_cell + end + private def tempdir diff --git a/config/locales/en.yml b/config/locales/en.yml index bdb781e4a..773218f9e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3690,6 +3690,7 @@ en: edit: "Edit" delete: "Delete" cancel: "Cancel" + copy: "Copy" duplicate: "Duplicate" okay: "Okay" back: "Back" From 39ce9c1781aba1b21bdc0694c6ae6138ec1d34f2 Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Wed, 8 Nov 2023 12:22:34 +0400 Subject: [PATCH 006/128] Enable access to "SciNote File Editor" app installers via the SciNote web app [SCI-9625] --- .../settings/account/addons_controller.rb | 1 + .../settings/account/addons/index.html.erb | 53 ++++++++++++++++++- config/locales/en.yml | 6 +++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/app/controllers/users/settings/account/addons_controller.rb b/app/controllers/users/settings/account/addons_controller.rb index c1777ba3c..1c89c96d4 100644 --- a/app/controllers/users/settings/account/addons_controller.rb +++ b/app/controllers/users/settings/account/addons_controller.rb @@ -9,6 +9,7 @@ module Users def index @label_printer_any = LabelPrinter.any? + @user_agent = request.user_agent end private diff --git a/app/views/users/settings/account/addons/index.html.erb b/app/views/users/settings/account/addons/index.html.erb index e1550715e..68f58a22a 100644 --- a/app/views/users/settings/account/addons/index.html.erb +++ b/app/views/users/settings/account/addons/index.html.erb @@ -7,7 +7,58 @@

<%= t('users.settings.account.addons.title') %>

- +
+
+
+
+

<%= t('users.settings.account.addons.desktop_app.title') %>

+

+ <%= t('users.settings.account.addons..desktop_app.description') %> +


+
+ <% if @user_agent =~ /Windows/ %> + <%= link_to '#', + class: 'btn btn-primary new-project-btn', + title: t('users.settings.account.addons.desktop_app.windows_button'), + remote: true do %> + + <% end %> +

<%= t('users.settings.account.addons.desktop_app.version') %> 5.16.5 (24419)

+ <% elsif @user_agent =~ /Mac OS/ %> + <%= link_to '#', + class: 'btn btn-primary new-project-btn', + title: t('users.settings.account.addons.desktop_app.macos_button'), + remote: true do %> + + <% end %> +

<%= t('users.settings.account.addons.desktop_app.version') %> 5.16.5 (24419)

+ <% else %> +
+
+ <%= link_to '#', + class: 'btn btn-primary new-project-btn', + title: t('users.settings.account.addons.desktop_app.macos_button'), + remote: true do %> + + <% end %> +

<%= t('users.settings.account.addons.desktop_app.version') %> 5.16.5 (24419)

+
+
+ <%= link_to '#', + class: 'btn btn-primary new-project-btn ml-2', + title: t('users.settings.account.addons.desktop_app.windows_button'), + remote: true do %> + + <% end %> +

<%= t('users.settings.account.addons.desktop_app.version') %> 5.16.5 (24419)

+
+
+ <% end %> +
+
+
+
+

<%= t('users.settings.account.addons.scinote_addons') %>

diff --git a/config/locales/en.yml b/config/locales/en.yml index a33939486..a3fbf0a12 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2719,6 +2719,12 @@ en: title: 'Zebra label printers' description: 'Print labels of custom styles and sizes in seconds flat from your PC or Mac via your Zebra printer connected via USB, Internet or LAN.' details: 'Details' + desktop_app: + title: 'SciNote File Editor desktop app' + description: 'Download the SciNote File Editor desktop app to automatically edit files using locally installed software' + macos_button: 'Download for macOS' + windows_button: 'Download for Windows' + version: 'Version' label_printer: fluics_printer: "FLUICS Print: Label printers" zebra_printer: 'Zebra label printers' From 85709d7b4319cc25c3cb87ecd1a619e12f5a0043 Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Thu, 16 Nov 2023 12:28:31 +0400 Subject: [PATCH 007/128] Fix setting of ASSET_SYNC_URL on the fronted [SCI-9665] --- app/controllers/asset_sync_controller.rb | 4 ++++ .../vue/shared/content/attachments/context_menu.vue | 3 ++- config/routes.rb | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/controllers/asset_sync_controller.rb b/app/controllers/asset_sync_controller.rb index 5cf619ccc..d957ee094 100644 --- a/app/controllers/asset_sync_controller.rb +++ b/app/controllers/asset_sync_controller.rb @@ -38,6 +38,10 @@ class AssetSyncController < ApplicationController render json: AssetSyncTokenSerializer.new(@asset_sync_token).as_json end + def api_url + render plain: Constants::ASSET_SYNC_URL + end + # private def conflicting_asset_copy_token diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index 43e262c4c..da89b61cd 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -142,7 +142,8 @@ try { const response = await axios.get(this.attachment.attributes.urls.open_locally); const data = response.data; - const syncUrl = GLOBAL_CONSTANTS.ASSET_SYNC_URL; + const syncUrlResponse = await axios.get('/asset_sync_api_url'); + const syncUrl = syncUrlResponse.data; await axios.post(syncUrl, data); } catch (error) { console.error("Error in request:", error); diff --git a/config/routes.rb b/config/routes.rb index 82b899f8a..5e01ca163 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1005,6 +1005,7 @@ Rails.application.routes.draw do get 'asset_sync/:asset_id', to: 'asset_sync#show', as: :asset_sync_show get 'asset_sync/:asset_id/download', to: 'asset_sync#download', as: :asset_sync_download put 'asset_sync', to: 'asset_sync#update' + get '/asset_sync_api_url', to: 'asset_sync#api_url' post 'global_activities', to: 'global_activities#index' From dd2611bb82631f82ef6744ef257f5eb0a6a59cd0 Mon Sep 17 00:00:00 2001 From: Ivan Kljun Date: Fri, 17 Nov 2023 07:41:12 +0100 Subject: [PATCH 008/128] Making asset sync feature switchable [SCI-9709] --- app/controllers/asset_sync_controller.rb | 7 ++++++- .../vue/shared/content/attachments/context_menu.vue | 10 ++++++---- app/serializers/asset_serializer.rb | 10 ++++++++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/app/controllers/asset_sync_controller.rb b/app/controllers/asset_sync_controller.rb index d957ee094..1ef9318f5 100644 --- a/app/controllers/asset_sync_controller.rb +++ b/app/controllers/asset_sync_controller.rb @@ -4,6 +4,7 @@ class AssetSyncController < ApplicationController skip_before_action :authenticate_user!, only: %i(update download) skip_before_action :verify_authenticity_token, only: %i(update download) before_action :authenticate_asset_sync_token!, only: %i(update download) + before_action :check_asset_sync def show asset = Asset.find_by(id: params[:asset_id]) @@ -42,7 +43,7 @@ class AssetSyncController < ApplicationController render plain: Constants::ASSET_SYNC_URL end - # private + private def conflicting_asset_copy_token Asset.transaction do @@ -74,4 +75,8 @@ class AssetSyncController < ApplicationController head :forbidden unless can_manage_asset?(@asset) end + + def check_asset_sync + render_404 if ENV['ASSET_SYNC_URL'].blank? + end end diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index da89b61cd..3ce4acfae 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -102,10 +102,12 @@ emit: 'open_scinote_editor', }) } - menu.push({ - text: this.i18n.t('Open_locally'), - emit: 'open_locally' - }) + if (this.attachment.attributes.urls.open_locally) { + menu.push({ + text: this.i18n.t('Open_locally'), + emit: 'open_locally' + }) + } menu.push({ text: this.i18n.t('Download'), url: this.attachment.attributes.urls.download, diff --git a/app/serializers/asset_serializer.rb b/app/serializers/asset_serializer.rb index 0b344a64a..9f601f7f2 100644 --- a/app/serializers/asset_serializer.rb +++ b/app/serializers/asset_serializer.rb @@ -131,14 +131,20 @@ class AssetSerializer < ActiveModel::Serializer start_edit_image: start_edit_image_path(object), delete: asset_destroy_path(object), move_targets: asset_move_tagets_path(object), - move: asset_move_path(object), - open_locally: asset_sync_show_path(object) + move: asset_move_path(object) ) end urls[:open_vector_editor_edit] = edit_gene_sequence_asset_path(object.id) if can_manage_asset?(user, object) + urls[:open_locally] = asset_sync_show_path(object) if can_manage_asset?(user, object) && can_open_locally? urls[:wopi_action] = object.get_action_url(user, 'embedview') if wopi && can_manage_asset?(user, object) urls[:blob] = rails_blob_path(object.file, disposition: 'attachment') if object.file.attached? urls end + + private + + def can_open_locally? + ENV['ASSET_SYNC_URL'].present? + end end From d0877de13c291cfc2af57292431b00dc978b92fe Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Thu, 23 Nov 2023 04:12:38 +0400 Subject: [PATCH 009/128] Add activity for updating a file via AssetSync [SCI-9710] --- app/controllers/asset_sync_controller.rb | 69 ++++++++++++++++++++++++ config/initializers/extends.rb | 11 ++-- config/locales/global_activities/en.yml | 6 +++ 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/app/controllers/asset_sync_controller.rb b/app/controllers/asset_sync_controller.rb index d957ee094..72d3e5f8f 100644 --- a/app/controllers/asset_sync_controller.rb +++ b/app/controllers/asset_sync_controller.rb @@ -35,6 +35,8 @@ class AssetSyncController < ApplicationController @asset.file.attach(io: request.body, filename: @asset.file.filename) @asset.touch + log_activity + render json: AssetSyncTokenSerializer.new(@asset_sync_token).as_json end @@ -42,6 +44,47 @@ class AssetSyncController < ApplicationController render plain: Constants::ASSET_SYNC_URL end + def log_activity + assoc ||= @asset.step + assoc ||= @asset.result + + case assoc + when Step + if assoc.protocol.in_module? + log_step_activity( + :edit_task_step_file_locally, + assoc, + assoc.my_module.project, + my_module: assoc.my_module.id, + file: @asset.file_name, + user: current_user.id, + step_position_original: @asset.step.position + 1, + step: assoc.id + ) + else + log_step_activity( + :edit_protocol_template_file_locally, + assoc, + nil, + { + file: @asset.file_name, + user: current_user.id, + step_position_original: @asset.step.position + 1, + step: assoc.id + } + ) + end + when Result + log_result_activity( + :edit_task_result_file_locally, + assoc, + file: @asset.file_name, + user: current_user.id, + result: Result.first.id + ) + end + end + # private def conflicting_asset_copy_token @@ -74,4 +117,30 @@ class AssetSyncController < ApplicationController head :forbidden unless can_manage_asset?(@asset) end + + def log_step_activity(type_of, step, project = nil, message_items = {}) + default_items = { step: step.id, + step_position: { id: step.id, value_for: 'position_plus_one' } } + message_items = default_items.merge(message_items) + + Activities::CreateActivityService + .call(activity_type: type_of, + owner: User.first, + subject: step.protocol, + team: step.protocol.team, + project: project, + message_items: message_items) + end + + def log_result_activity(type_of, result, message_items) + Activities::CreateActivityService + .call(activity_type: type_of, + owner: current_user, + subject: result, + team: result.my_module.team, + project: result.my_module.project, + message_items: { + result: result.id + }.merge(message_items)) + end end diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb index 73cd9b033..1a6f08e06 100644 --- a/config/initializers/extends.rb +++ b/config/initializers/extends.rb @@ -492,16 +492,19 @@ class Extends sequence_on_result_edited: 288, sequence_on_result_deleted: 289, sequence_on_result_moved: 290, - move_chemical_structure_on_result: 291 + move_chemical_structure_on_result: 291, + edit_task_step_file_locally: 292, + edit_protocol_template_file_locally: 293, + edit_task_result_file_locally: 294 } ACTIVITY_GROUPS = { projects: [*0..7, 32, 33, 34, 95, 108, 65, 109, *158..162, 241, 242, 243], - task_results: [23, 26, 25, 42, 24, 40, 41, 99, 110, 122, 116, 128, 169, 172, 178, *257..273, *284..291], + task_results: [23, 26, 25, 42, 24, 40, 41, 99, 110, 122, 116, 128, 169, 172, 178, *257..273, *284..291, 294], task: [8, 58, 9, 59, *10..14, 35, 36, 37, 53, 54, *60..63, 138, 139, 140, 64, 66, 106, 126, 120, 132, *146..148, 166, 246, 247, 248], task_protocol: [15, 22, 16, 18, 19, 20, 21, 17, 38, 39, 100, 111, 45, 46, 47, 121, 124, 115, 118, 127, 130, 137, - 217, 168, 171, 177, 184, 185, 188, 189, *192..203, 222, 224, 225, 226, 236, *249..252, *274..278], + 217, 168, 171, 177, 184, 185, 188, 189, *192..203, 222, 224, 225, 226, 236, *249..252, *274..278, 292], task_inventory: [55, 56, 146, 147, 183], experiment: [*27..31, 57, 141, 165], reports: [48, 50, 49, 163, 164], @@ -510,7 +513,7 @@ class Extends protocol_repository: [80, 103, 89, 87, 79, 90, 91, 88, 85, 86, 84, 81, 82, 83, 101, 112, 123, 125, 117, 119, 129, 131, 170, 173, 179, 187, 186, 190, 191, *204..215, 220, 221, 223, 227, 228, 229, *230..235, - *237..240, *253..256, *279..283], + *237..240, *253..256, *279..283, 293], team: [92, 94, 93, 97, 104, 244, 245], label_templates: [*216..219] } diff --git a/config/locales/global_activities/en.yml b/config/locales/global_activities/en.yml index 45b3756fe..bb3ae606a 100644 --- a/config/locales/global_activities/en.yml +++ b/config/locales/global_activities/en.yml @@ -316,6 +316,9 @@ en: result_text_moved_html: "%{user} moved text %{text_name} from result %{result_original} to result %{result_destination}." result_table_moved_html: "%{user} moved table %{table_name} from result %{result_original} to result %{result_destination}." move_chemical_structure_on_result_html: "%{user} moved chemical structure %{file} from result %{result_original} to result %{result_destination}." + edit_task_step_file_locally_html: "%{user} locally edited file %{file} on protocol's step %{step_position_original} %{step} on task %{my_module}" + edit_protocol_template_file_locally_html: "%{user} locally edited file %{file} on protocol's step %{step_position_original} %{step} with SciNote Edit in Protocol repository" + edit_task_result_file_locally_html: "%{user} locally edited file %{file} on result %{result}" activity_name: create_project: "Project created" rename_project: "Project renamed" @@ -586,6 +589,9 @@ en: result_text_moved: "Result text moved" result_table_moved: "Result table moved" move_chemical_structure_on_result: "Chemical structure on result moved" + edit_task_step_file_locally: "File on task step edited locally" + edit_protocol_template_file_locally: "File on protocol templates edited locally" + edit_task_result_file_locally: "File on task result edited locally" activity_group: projects: "Projects" From 235d94e1cfac9c1ecfcd2c631d865f56247e5801 Mon Sep 17 00:00:00 2001 From: Martin Artnik Date: Tue, 5 Dec 2023 12:35:55 +0100 Subject: [PATCH 010/128] Implement SciNote edit button with checks and info [SCI-9756] --- .../content/attachments/context_menu.vue | 23 +++----- .../attachments/mixins/open_locally.js | 56 +++++++++++++++++++ app/permissions/asset.rb | 4 ++ app/serializers/asset_serializer.rb | 19 ++++--- config/initializers/extends.rb | 3 +- config/locales/en.yml | 3 +- 6 files changed, 83 insertions(+), 25 deletions(-) create mode 100644 app/javascript/vue/shared/content/attachments/mixins/open_locally.js diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index 3ce4acfae..308c0b0d3 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -52,13 +52,14 @@ import deleteAttachmentModal from './delete_modal.vue' import moveAssetModal from '../modal/move.vue' import MoveMixin from './mixins/move.js' + import OpenLocallyMixin from './mixins/open_locally.js' import MenuDropdown from '../../menu_dropdown.vue' import axios from '../../../../packs/custom_axios' export default { name: 'contextMenu', components: { deleteAttachmentModal, moveAssetModal, MenuDropdown }, - mixins: [MoveMixin], + mixins: [MoveMixin, OpenLocallyMixin], props: { attachment: { type: Object, @@ -102,9 +103,13 @@ emit: 'open_scinote_editor', }) } - if (this.attachment.attributes.urls.open_locally) { + if (this.canOpenLocally) { + const text = this.localAppName ? + this.i18n.t('attachments.open_locally_in', { application: this.localAppName }) : + this.i18n.t('attachments.open_locally') + menu.push({ - text: this.i18n.t('Open_locally'), + text: text, emit: 'open_locally' }) } @@ -140,18 +145,6 @@ } }, methods: { - async openLocally() { - try { - const response = await axios.get(this.attachment.attributes.urls.open_locally); - const data = response.data; - const syncUrlResponse = await axios.get('/asset_sync_api_url'); - const syncUrl = syncUrlResponse.data; - await axios.post(syncUrl, data); - } catch (error) { - console.error("Error in request:", error); - } - }, - // TODO: add method to handle get to SciNote and then post to local URL changeViewMode(viewMode) { this.$emit('attachment:viewMode', viewMode) $.ajax({ diff --git a/app/javascript/vue/shared/content/attachments/mixins/open_locally.js b/app/javascript/vue/shared/content/attachments/mixins/open_locally.js new file mode 100644 index 000000000..d49baf054 --- /dev/null +++ b/app/javascript/vue/shared/content/attachments/mixins/open_locally.js @@ -0,0 +1,56 @@ +import axios from '../../../../../packs/custom_axios.js'; + +export default { + data() { + return { + localAppName: null, + scinoteEditRunning: false + }; + }, + computed: { + canOpenLocally() { + return this.scinoteEditRunning && + !!this.attachment.attributes.urls.open_locally && + this.attachment.attributes.asset_type !== 'gene_sequence' && + this.attachment.attributes.asset_type !== 'marvinjs' + } + }, + mounted() { + this.$nextTick(() => { + this.fetchLocalAppInfo(); + }); + }, + methods: { + async fetchLocalAppInfo() { + try { + const statusResponse = await axios.get( + `${this.attachment.attributes.urls.open_locally_api}/status` + ); + + if (statusResponse.status === 200) { + this.scinoteEditRunning = true; + } else { + return; + } + + const response = await axios.get( + `${this.attachment.attributes.urls.open_locally_api}/default-application/${this.attachment.attributes.file_extension}` + ); + + this.localAppName = response.data.application; + } catch (error) { + console.error("Error in request: ", error); + } + }, + async openLocally() { + try { + const response = await axios.get(this.attachment.attributes.urls.open_locally); + const data = response.data; + await axios.post(this.attachment.attributes.urls.open_locally_api + '/download', data); + } catch (error) { + console.error("Error in request:", error); + } + } + } +} + diff --git a/app/permissions/asset.rb b/app/permissions/asset.rb index 7bf9821e8..fca1cde59 100644 --- a/app/permissions/asset.rb +++ b/app/permissions/asset.rb @@ -31,4 +31,8 @@ Canaid::Permissions.register_for(Asset) do end end end + + can :open_asset_locally do |_user, asset| + ENV['ASSET_SYNC_URL'].present? + end end diff --git a/app/serializers/asset_serializer.rb b/app/serializers/asset_serializer.rb index 9f601f7f2..9dcbfade1 100644 --- a/app/serializers/asset_serializer.rb +++ b/app/serializers/asset_serializer.rb @@ -8,7 +8,7 @@ class AssetSerializer < ActiveModel::Serializer include InputSanitizeHelper include ApplicationHelper - attributes :file_name, :view_mode, :icon, :urls, :updated_at_formatted, + attributes :file_name, :file_extension, :view_mode, :icon, :urls, :updated_at_formatted, :file_size, :medium_preview, :large_preview, :asset_type, :wopi, :wopi_context, :pdf_previewable, :file_size_formatted, :asset_order, :updated_at, :metadata, :image_editable, :image_context, :pdf, :attached, :parent_type @@ -21,6 +21,10 @@ class AssetSerializer < ActiveModel::Serializer object.render_file_name end + def file_extension + File.extname(object.file_name)[1..] + end + def updated_at object.updated_at.to_i end @@ -135,16 +139,15 @@ class AssetSerializer < ActiveModel::Serializer ) end urls[:open_vector_editor_edit] = edit_gene_sequence_asset_path(object.id) if can_manage_asset?(user, object) - urls[:open_locally] = asset_sync_show_path(object) if can_manage_asset?(user, object) && can_open_locally? + + if can_manage_asset?(user, object) && can_open_asset_locally?(user, object) + urls[:open_locally] = asset_sync_show_path(object) + urls[:open_locally_api] = Constants::ASSET_SYNC_URL + end + urls[:wopi_action] = object.get_action_url(user, 'embedview') if wopi && can_manage_asset?(user, object) urls[:blob] = rails_blob_path(object.file, disposition: 'attachment') if object.file.attached? urls end - - private - - def can_open_locally? - ENV['ASSET_SYNC_URL'].present? - end end diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb index 73cd9b033..a5d9926fd 100644 --- a/config/initializers/extends.rb +++ b/config/initializers/extends.rb @@ -611,7 +611,8 @@ class Extends ) if Constants::ASSET_SYNC_URL && EXTERNAL_SERVICES.exclude?(Constants::ASSET_SYNC_URL) - EXTERNAL_SERVICES << Constants::ASSET_SYNC_URL + asset_sync_url = URI.parse(Constants::ASSET_SYNC_URL) + EXTERNAL_SERVICES << "#{asset_sync_url.host}:#{asset_sync_url.port}" end COLORED_BACKGROUND_ACTIONS = %w( diff --git a/config/locales/en.yml b/config/locales/en.yml index ea1addb34..9535cd0b4 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -395,6 +395,8 @@ en: add: "ADD" sort_by: "SORT BY" attachments_view_mode: "ALL ATTACHMENTS VIEW SIZE" + open_locally_in: "Open in %{application}" + open_locally: "Open locally" new: description: 'New' uploading: 'Uploading' @@ -3867,7 +3869,6 @@ en: Add: "Add" Asset: "File" Assets: "Files" - Open_locally: "Open locally" Download: "Download" Edit: "Edit" Save: "Save" From 2dfd270df207c1d08f8e354e1c8508b04a3f0ed0 Mon Sep 17 00:00:00 2001 From: Ivan Kljun Date: Tue, 5 Dec 2023 14:47:46 +0100 Subject: [PATCH 011/128] Add conflict check for WOPI lock AssetSyncController [SCI-9758] --- app/models/asset_sync_token.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/asset_sync_token.rb b/app/models/asset_sync_token.rb index 8c1224366..0729fb7c9 100644 --- a/app/models/asset_sync_token.rb +++ b/app/models/asset_sync_token.rb @@ -18,7 +18,7 @@ class AssetSyncToken < ApplicationRecord end def conflicts?(token) - version_token != token + asset.locked? || version_token != token end private From 804ee30169523551d359d7d3517cf86c62494a30 Mon Sep 17 00:00:00 2001 From: Martin Artnik Date: Tue, 5 Dec 2023 15:39:57 +0100 Subject: [PATCH 012/128] Add scheme to asset sync url in extends --- config/initializers/extends.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb index a5d9926fd..ae64239b0 100644 --- a/config/initializers/extends.rb +++ b/config/initializers/extends.rb @@ -612,7 +612,7 @@ class Extends if Constants::ASSET_SYNC_URL && EXTERNAL_SERVICES.exclude?(Constants::ASSET_SYNC_URL) asset_sync_url = URI.parse(Constants::ASSET_SYNC_URL) - EXTERNAL_SERVICES << "#{asset_sync_url.host}:#{asset_sync_url.port}" + EXTERNAL_SERVICES << "#{asset_sync_url.scheme}://#{asset_sync_url.host}:#{asset_sync_url.port}" end COLORED_BACKGROUND_ACTIONS = %w( From b1554624967e9d64f2e7f8ca9ae0668b59f63500 Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Wed, 6 Dec 2023 11:54:46 +0400 Subject: [PATCH 013/128] updated numbering to fit develop branch --- config/initializers/extends.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb index 3261a98da..fd858ab75 100644 --- a/config/initializers/extends.rb +++ b/config/initializers/extends.rb @@ -493,18 +493,18 @@ class Extends sequence_on_result_deleted: 289, sequence_on_result_moved: 290, move_chemical_structure_on_result: 291, - edit_task_step_file_locally: 292, - edit_protocol_template_file_locally: 293, - edit_task_result_file_locally: 294 + edit_task_step_file_locally: 293, + edit_protocol_template_file_locally: 294, + edit_task_result_file_locally: 295 } ACTIVITY_GROUPS = { projects: [*0..7, 32, 33, 34, 95, 108, 65, 109, *158..162, 241, 242, 243], - task_results: [23, 26, 25, 42, 24, 40, 41, 99, 110, 122, 116, 128, 169, 172, 178, *257..273, *284..291, 294], + task_results: [23, 26, 25, 42, 24, 40, 41, 99, 110, 122, 116, 128, 169, 172, 178, *257..273, *284..291, 295], task: [8, 58, 9, 59, *10..14, 35, 36, 37, 53, 54, *60..63, 138, 139, 140, 64, 66, 106, 126, 120, 132, *146..148, 166, 246, 247, 248], task_protocol: [15, 22, 16, 18, 19, 20, 21, 17, 38, 39, 100, 111, 45, 46, 47, 121, 124, 115, 118, 127, 130, 137, - 217, 168, 171, 177, 184, 185, 188, 189, *192..203, 222, 224, 225, 226, 236, *249..252, *274..278, 292], + 217, 168, 171, 177, 184, 185, 188, 189, *192..203, 222, 224, 225, 226, 236, *249..252, *274..278, 293], task_inventory: [55, 56, 146, 147, 183], experiment: [*27..31, 57, 141, 165], reports: [48, 50, 49, 163, 164], @@ -513,7 +513,7 @@ class Extends protocol_repository: [80, 103, 89, 87, 79, 90, 91, 88, 85, 86, 84, 81, 82, 83, 101, 112, 123, 125, 117, 119, 129, 131, 170, 173, 179, 187, 186, 190, 191, *204..215, 220, 221, 223, 227, 228, 229, *230..235, - *237..240, *253..256, *279..283, 293], + *237..240, *253..256, *279..283, 294], team: [92, 94, 93, 97, 104, 244, 245], label_templates: [*216..219] } From d93b4c6b78b0f5748b048d42d2b8e9d98217332a Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Fri, 8 Dec 2023 12:25:28 +0400 Subject: [PATCH 014/128] Update terminology for opening attached files --- config/locales/en.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 9bcc9c7f1..1a25225f1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1805,10 +1805,10 @@ en: destroy: success_flash: "File result successfully deleted." wopi_open_file: "Open in %{app}" - wopi_edit_file: "Edit in %{app}" - wopi_word: "Word for the web" - wopi_excel: "Excel for the web" - wopi_powerpoint: "PowerPoint for the web" + wopi_edit_file: "Open in %{app}" + wopi_word: "MS Word online" + wopi_excel: "Excel online" + wopi_powerpoint: "PowerPoint online" error_flash: 'Something went wrong! Please try again later.' result_tables: @@ -3522,8 +3522,8 @@ en: forbidden: 'You do not have permission to add files.' not_found: 'Element not found.' file_preview: - edit_in_scinote: "Edit" - edit_in_marvinjs: "Edit in Marvin JS" + edit_in_scinote: "Open in image editor" + edit_in_marvinjs: "Open in Marvin JS" context_menu: set_view_size: "SET PREVIEW SIZE" delete: "Delete" @@ -3957,7 +3957,7 @@ en: new_sequence: "Sequence" new_sequence_file: "New sequence" default_sequence_name: "New sequence" - edit_sequence: "Edit in Sequence editor" + edit_sequence: "Open in sequence editor" sequence_name_placeholder: "Click here to enter sequence name" editor: tooltips: From 7de19c31ece361494063765c77269f7f3dad0195 Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Wed, 13 Dec 2023 23:54:41 +0400 Subject: [PATCH 015/128] Implement the Open Locally button on file previews [SCI-9757] --- app/javascript/packs/vue/open_locally_menu.js | 10 +++ .../content/attachments/open_locally_menu.vue | 65 +++++++++++++++++++ .../shared/file_preview/_content.html.erb | 11 ++-- config/webpack/webpack.config.js | 1 + 4 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 app/javascript/packs/vue/open_locally_menu.js create mode 100644 app/javascript/vue/shared/content/attachments/open_locally_menu.vue diff --git a/app/javascript/packs/vue/open_locally_menu.js b/app/javascript/packs/vue/open_locally_menu.js new file mode 100644 index 000000000..4fa8be201 --- /dev/null +++ b/app/javascript/packs/vue/open_locally_menu.js @@ -0,0 +1,10 @@ +/* global notTurbolinksPreview */ + +import { createApp } from 'vue/dist/vue.esm-bundler.js'; +import OpenLocallyMenu from '../../vue/shared/content/attachments/open_locally_menu.vue'; +import { mountWithTurbolinks } from './helpers/turbolinks.js'; + +const app = createApp({}); +app.component('OpenLocallyMenu', OpenLocallyMenu); +app.config.globalProperties.i18n = window.I18n; +mountWithTurbolinks(app, '#openLocallyMenu'); diff --git a/app/javascript/vue/shared/content/attachments/open_locally_menu.vue b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue new file mode 100644 index 000000000..a59f1521b --- /dev/null +++ b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue @@ -0,0 +1,65 @@ + + + diff --git a/app/views/shared/file_preview/_content.html.erb b/app/views/shared/file_preview/_content.html.erb index 36fbbf188..31fd8e0d8 100644 --- a/app/views/shared/file_preview/_content.html.erb +++ b/app/views/shared/file_preview/_content.html.erb @@ -3,13 +3,9 @@
<% if can_edit && !preview %> <% if wopi_enabled? && wopi_file?(asset) %> - <% edit_supported, title = wopi_file_edit_button_status(asset) %> - <%= render partial: 'assets/wopi/file_wopi_controls', - locals: { - asset: asset, - edit_supported: edit_supported, - title: title - } %> +
+ +
<% elsif asset.file.metadata[:asset_type] == 'marvinjs' %>
+ + + + - + - + - + - + @@ -125,13 +141,15 @@ import ContextMenuMixin from './mixins/context_menu.js' import ContextMenu from './context_menu.vue' import deleteAttachmentModal from './delete_modal.vue' + import MenuDropdown from '../../../shared/menu_dropdown.vue' import MoveAssetModal from '../modal/move.vue' import MoveMixin from './mixins/move.js' + import OpenLocallyMixin from './mixins/open_locally.js' export default { name: 'thumbnailAttachment', - mixins: [ContextMenuMixin, AttachmentMovedMixin, MoveMixin], - components: { ContextMenu, deleteAttachmentModal, MoveAssetModal}, + mixins: [ContextMenuMixin, AttachmentMovedMixin, MoveMixin, OpenLocallyMixin], + components: { ContextMenu, deleteAttachmentModal, MoveAssetModal, MenuDropdown }, props: { attachment: { type: Object, @@ -148,6 +166,49 @@ deleteModal: false }; }, + computed: { + openOptions() { + let options = []; + if (this.attachment.attributes.wopi && this.attachment.attributes.urls.edit_asset) { + options.push({ + text: this.attachment.attributes.wopi_context.button_text, + url: this.attachment.attributes.urls.edit_asset, + url_target: '_blank' + }); + } + if (this.attachment.attributes.asset_type === 'gene_sequence' && this.attachment.attributes.urls.open_vector_editor_edit) { + options.push({ + text: this.i18n.t('open_vector_editor.edit_sequence'), + emit: 'open_ove_editor', + }); + } + if (this.attachment.attributes.asset_type === 'marvinjs' && this.attachment.attributes.urls.marvin_js_start_edit) { + options.push({ + text: this.i18n.t('assets.file_preview.edit_in_marvinjs'), + emit: 'open_marvinjs_editor', + }) + } + if (this.attachment.attributes.asset_type !== 'marvinjs' + && this.attachment.attributes.image_editable + && this.attachment.attributes.urls.start_edit_image) { + options.push({ + text: this.i18n.t('assets.file_preview.edit_in_scinote'), + emit: 'open_scinote_editor', + }) + } + if (this.canOpenLocally) { + const text = this.localAppName ? + this.i18n.t('attachments.open_locally_in', { application: this.localAppName }) : + this.i18n.t('attachments.open_locally') + + options.push({ + text: text, + emit: 'open_locally' + }); + } + return options; + }, + }, mounted() { $(this.$nextTick(function() { $(`.attachment-preview img`) diff --git a/app/javascript/vue/shared/menu_dropdown.vue b/app/javascript/vue/shared/menu_dropdown.vue index 8ab614260..da26c12b6 100644 --- a/app/javascript/vue/shared/menu_dropdown.vue +++ b/app/javascript/vue/shared/menu_dropdown.vue @@ -1,6 +1,11 @@ diff --git a/config/locales/en.yml b/config/locales/en.yml index f6de3c408..047b45d4c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3560,6 +3560,10 @@ en: empty_office_file: description: "The file is empty. Please add some data before saving the file." reload: "Reload file" + asset_sync: + body_text_html: "The specified application for accessing the %{file_name} is not preconfigured. To successfully open this file, please set up the appropriate application in your local environment beforehand.

" + no_predefined_app: "I understand" + set_up_app: "Set up an application to open this file" atwho: no_results: From de706fc3fb26236bee184f6c7f0564e886ebb70f Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Fri, 15 Dec 2023 01:55:26 +0400 Subject: [PATCH 019/128] Implement the SciNote Edit launching application modal [SCI-9841] --- .../content/attachments/context_menu.vue | 18 ++++++-- .../edit_launching_application_modal.vue | 41 +++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index 308c0b0d3..bc2acc47e 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -30,7 +30,7 @@ @open_ove_editor="openOVEditor(attachment.attributes.urls.open_vector_editor_edit)" @open_marvinjs_editor="openMarvinJsEditor" @open_scinote_editor="openScinoteEditor" - @open_locally="openLocally" + @open_locally="openLocallyButton" @delete="deleteModal = true" @viewMode="changeViewMode" @move="showMoveModal" @@ -41,6 +41,12 @@ @confirm="deleteAttachment" @cancel="deleteModal = false" /> + import deleteAttachmentModal from './delete_modal.vue' + import editLaunchingApplicationModal from './edit_launching_application_modal.vue' import moveAssetModal from '../modal/move.vue' import MoveMixin from './mixins/move.js' import OpenLocallyMixin from './mixins/open_locally.js' @@ -58,7 +65,7 @@ export default { name: 'contextMenu', - components: { deleteAttachmentModal, moveAssetModal, MenuDropdown }, + components: { deleteAttachmentModal, moveAssetModal, MenuDropdown, editLaunchingApplicationModal }, mixins: [MoveMixin, OpenLocallyMixin], props: { attachment: { @@ -70,7 +77,8 @@ data() { return { viewModeOptions: ['inline', 'thumbnail', 'list'], - deleteModal: false + deleteModal: false, + editAppModal: false } }, computed: { @@ -171,6 +179,10 @@ ); $(this.$refs.marvinjsEditButton).trigger('click'); }, + openLocallyButton() { + this.editAppModal = true; + this.$emit(this.openLocally()) + }, openScinoteEditor() { $(this.$refs.imageEditButton).trigger('click'); }, diff --git a/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue b/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue new file mode 100644 index 000000000..d3fc20a66 --- /dev/null +++ b/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue @@ -0,0 +1,41 @@ + + From 23ede59730d365f27d2e5f20037d48e099d64efa Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Tue, 19 Dec 2023 12:19:19 +0400 Subject: [PATCH 020/128] hound fix --- app/javascript/packs/vue/open_locally_menu.js | 2 -- .../vue/shared/content/attachments/open_locally_menu.vue | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/javascript/packs/vue/open_locally_menu.js b/app/javascript/packs/vue/open_locally_menu.js index 4fa8be201..d7e6d6c2b 100644 --- a/app/javascript/packs/vue/open_locally_menu.js +++ b/app/javascript/packs/vue/open_locally_menu.js @@ -1,5 +1,3 @@ -/* global notTurbolinksPreview */ - import { createApp } from 'vue/dist/vue.esm-bundler.js'; import OpenLocallyMenu from '../../vue/shared/content/attachments/open_locally_menu.vue'; import { mountWithTurbolinks } from './helpers/turbolinks.js'; diff --git a/app/javascript/vue/shared/content/attachments/open_locally_menu.vue b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue index a59f1521b..64bcf9f6b 100644 --- a/app/javascript/vue/shared/content/attachments/open_locally_menu.vue +++ b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue @@ -48,16 +48,16 @@ }) } if (this.canOpenLocally) { - console.log(this.localAppName) - const text = this.localAppName ? - this.i18n.t('attachments.open_locally_in', { application: this.localAppName }) : - this.i18n.t('attachments.open_locally') + const text = this.localAppName + ? this.i18n.t('attachments.open_locally_in', { application: this.localAppName }) + : this.i18n.t('attachments.open_locally') menu.push({ text: text, emit: 'open_locally' }) } + return menu; } } From 5305c8ad213a60610d87551e9e753f9bd2da2faf Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Wed, 20 Dec 2023 13:26:02 +0400 Subject: [PATCH 021/128] hound fix --- .../content/attachments/context_menu.vue | 2 +- .../edit_launching_application_modal.vue | 37 ++++++++++--------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index bc2acc47e..1ffac8c65 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -181,7 +181,7 @@ }, openLocallyButton() { this.editAppModal = true; - this.$emit(this.openLocally()) + this.$emit(this.openLocally()); }, openScinoteEditor() { $(this.$refs.imageEditButton).trigger('click'); diff --git a/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue b/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue index d3fc20a66..36225cdff 100644 --- a/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue +++ b/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue @@ -9,7 +9,10 @@
- From cc8a10edb037af11ac0aad211b2a468ac44cd305 Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Fri, 29 Dec 2023 12:53:46 +0400 Subject: [PATCH 022/128] "Move" feature for multiple selected tasks and experiments (bulk action) --- app/controllers/experiments_controller.rb | 50 ++++++++++++-------- app/services/toolbars/experiments_service.rb | 8 +--- app/services/toolbars/my_modules_service.rb | 6 +-- app/views/experiments/_move_modal.html.erb | 15 +++--- config/locales/en.yml | 2 +- 5 files changed, 43 insertions(+), 38 deletions(-) diff --git a/app/controllers/experiments_controller.rb b/app/controllers/experiments_controller.rb index 32542e5a2..fd4802707 100644 --- a/app/controllers/experiments_controller.rb +++ b/app/controllers/experiments_controller.rb @@ -10,17 +10,17 @@ class ExperimentsController < ApplicationController before_action :load_project, only: %i(new create archive_group restore_group) before_action :load_experiment, except: %i(new create archive_group restore_group - inventory_assigning_experiment_filter actions_toolbar) + inventory_assigning_experiment_filter actions_toolbar move_modal move) + before_action :load_experiments, only: %i(move_modal move) before_action :check_read_permissions, except: %i(edit archive clone move new create archive_group restore_group - inventory_assigning_experiment_filter actions_toolbar) + inventory_assigning_experiment_filter actions_toolbar move_modal) before_action :check_canvas_read_permissions, only: %i(canvas) before_action :check_create_permissions, only: %i(new create) before_action :check_manage_permissions, only: %i(edit batch_clone_my_modules) before_action :check_update_permissions, only: %i(update) before_action :check_archive_permissions, only: :archive before_action :check_clone_permissions, only: %i(clone_modal clone) - before_action :check_move_permissions, only: %i(move_modal move) before_action :set_inline_name_editing, only: %i(canvas table module_archive) before_action :set_breadcrumbs_items, only: %i(canvas table module_archive) before_action :set_navigator, only: %i(canvas module_archive table) @@ -274,7 +274,7 @@ class ExperimentsController < ApplicationController # GET: move_modal_experiment_path(id) def move_modal - @projects = @experiment.movable_projects(current_user) + @projects = @experiments.first.movable_projects(current_user) render json: { html: render_to_string(partial: 'move_modal', formats: :html) } @@ -297,23 +297,28 @@ class ExperimentsController < ApplicationController # POST: move_experiment(id) def move - service = Experiments::MoveToProjectService - .call(experiment_id: @experiment.id, - project_id: move_experiment_param, - user_id: current_user.id) - if service.succeed? - flash[:success] = t('experiments.move.success_flash', - experiment: @experiment.name) - status = :ok - view_state = @experiment.current_view_state(current_user) - view_type = view_state.state['my_modules']['view_type'] || 'canvas' - path = view_mode_redirect_url(view_type) - else - message = "#{service.errors.values.join('. ')}." - status = :unprocessable_entity - end + move_responses = [] - render json: { message: message, path: path }, status: status + @experiments.each do |experiment| + @experiment = experiment + service = Experiments::MoveToProjectService + .call(experiment_id: experiment.id, + project_id: params[:project_id], + user_id: current_user.id) + if service.succeed? + flash[:success] = t('experiments.move.success_flash', experiment: experiment.name) + status = :ok + view_state = experiment.current_view_state(current_user) + view_type = view_state.state['my_modules']['view_type'] || 'canvas' + path = view_mode_redirect_url(view_type) + else + message = "#{service.errors.values.join('. ')}." + status = :unprocessable_entity + end + + move_responses << {message: message, path: path, status: status } + end + render json: move_responses end def move_modules_modal @@ -531,6 +536,11 @@ class ExperimentsController < ApplicationController render_404 unless @experiment end + def load_experiments + @experiments = Experiment.preload(user_assignments: %i(user user_role)).where(id: params[:ids]) + render_404 unless @experiments + end + def load_project @project = Project.find_by(id: params[:project_id]) render_404 unless @project diff --git a/app/services/toolbars/experiments_service.rb b/app/services/toolbars/experiments_service.rb index 414bc05f6..a4a65affe 100644 --- a/app/services/toolbars/experiments_service.rb +++ b/app/services/toolbars/experiments_service.rb @@ -87,18 +87,14 @@ module Toolbars end def move_action - return unless @single - - experiment = @experiments.first - - return unless can_move_experiment?(experiment) + return unless @experiments.all? { |experiment| can_move_experiment?(experiment) } { name: 'move', label: I18n.t('experiments.toolbar.move_button'), icon: 'sn-icon sn-icon-move', button_class: 'move-experiments-btn', - path: move_modal_experiments_path(id: experiment.id), + path: move_modal_experiments_path(ids: @experiments.map(&:id)), type: 'remote-modal' } end diff --git a/app/services/toolbars/my_modules_service.rb b/app/services/toolbars/my_modules_service.rb index c8a7f6fac..989fb7e88 100644 --- a/app/services/toolbars/my_modules_service.rb +++ b/app/services/toolbars/my_modules_service.rb @@ -88,11 +88,7 @@ module Toolbars end def move_action - return unless @single - - my_module = @my_modules.first - - return unless can_move_my_module?(my_module) + return unless @my_modules.all? { |my_module| can_move_my_module?(my_module) } { name: 'move', diff --git a/app/views/experiments/_move_modal.html.erb b/app/views/experiments/_move_modal.html.erb index 68d45ee4f..e2cc90aa1 100644 --- a/app/views/experiments/_move_modal.html.erb +++ b/app/views/experiments/_move_modal.html.erb @@ -1,10 +1,10 @@ From 888171c22c128b5e8d6d4fba5ddde19789fe112a Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Thu, 4 Jan 2024 02:58:18 +0400 Subject: [PATCH 029/128] hound fix --- .../content/attachments/edit_launching_application_modal.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue b/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue index cb01d7491..16a70509c 100644 --- a/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue +++ b/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue @@ -40,5 +40,5 @@ $(this.$refs.modal).modal('hide'); } } - } + }; From 473fad28de6ee89daed66940567de346a83c8742 Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Thu, 4 Jan 2024 02:59:08 +0400 Subject: [PATCH 030/128] hound fix --- .../edit_launching_application_modal.vue | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue b/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue index 16a70509c..bbaf64f6a 100644 --- a/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue +++ b/app/javascript/vue/shared/content/attachments/edit_launching_application_modal.vue @@ -24,21 +24,21 @@
From b6a84ecd87d6b4f35f5fa92b7bdb7524dd08dbe4 Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Thu, 4 Jan 2024 03:04:17 +0400 Subject: [PATCH 031/128] hound fix --- .../vue/shared/content/attachments/context_menu.vue | 4 ++-- .../attachments/edit_launching_application_modal.vue | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index 1ffac8c65..a49793318 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -56,7 +56,7 @@ From 509024458d58603522aadf44cd93533f3c1d7cc5 Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Thu, 4 Jan 2024 03:13:21 +0400 Subject: [PATCH 032/128] new linter fixes --- .../content/attachments/open_locally_menu.vue | 84 ++++++++++--------- config/webpack/webpack.config.js | 2 +- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/app/javascript/vue/shared/content/attachments/open_locally_menu.vue b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue index 64bcf9f6b..d1beba9b1 100644 --- a/app/javascript/vue/shared/content/attachments/open_locally_menu.vue +++ b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue @@ -1,7 +1,9 @@ diff --git a/config/webpack/webpack.config.js b/config/webpack/webpack.config.js index ae1133d10..e815153c8 100644 --- a/config/webpack/webpack.config.js +++ b/config/webpack/webpack.config.js @@ -46,7 +46,7 @@ const entryList = { vue_components_export_stock_consumption_modal: './app/javascript/packs/vue/export_stock_consumption_modal.js', vue_components_manage_stock_value_modal: './app/javascript/packs/vue/manage_stock_value_modal.js', vue_legacy_datetime_picker: './app/javascript/packs/vue/legacy/datetime_picker.js', - vue_open_locally_menu: './app/javascript/packs/vue/open_locally_menu.js' + vue_open_locally_menu: './app/javascript/packs/vue/open_locally_menu.js', } // Engine pack loading based on https://github.com/rails/webpacker/issues/348#issuecomment-635480949 From 78747911b706fd5bf63b9eb81a7a63f89f0e8d35 Mon Sep 17 00:00:00 2001 From: Martin Artnik Date: Thu, 4 Jan 2024 10:40:28 +0100 Subject: [PATCH 033/128] Fix conflicts in asset sync caused by preview generation [SCI-9935] --- app/models/asset_sync_token.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/asset_sync_token.rb b/app/models/asset_sync_token.rb index 0729fb7c9..5b80255aa 100644 --- a/app/models/asset_sync_token.rb +++ b/app/models/asset_sync_token.rb @@ -10,7 +10,7 @@ class AssetSyncToken < ApplicationRecord validates :token, uniqueness: true, presence: true def version_token - asset.updated_at.to_i.to_s + asset.file.checksum end def token_valid? From 2306496c3b328a4ad2025290a1a68ed9c6e85186 Mon Sep 17 00:00:00 2001 From: Ivan Kljun Date: Thu, 4 Jan 2024 10:15:06 +0100 Subject: [PATCH 034/128] Apply hound suggestions [SCI-9862] --- .../content/attachments/context_menu.vue | 242 +++++++++--------- .../attachments/mixins/open_locally.js | 2 +- .../shared/content/attachments/thumbnail.vue | 92 +++---- .../content/modal/no_predefined_app_modal.vue | 33 +-- 4 files changed, 185 insertions(+), 184 deletions(-) diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index ea883c793..cf90de0e6 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -56,132 +56,132 @@ diff --git a/app/javascript/vue/shared/content/attachments/mixins/open_locally.js b/app/javascript/vue/shared/content/attachments/mixins/open_locally.js index 9065fbead..5c8014ca8 100644 --- a/app/javascript/vue/shared/content/attachments/mixins/open_locally.js +++ b/app/javascript/vue/shared/content/attachments/mixins/open_locally.js @@ -44,7 +44,7 @@ export default { }, async openLocally() { if (this.localAppName === null) { - this.showNoPredefinedAppModal = true + this.showNoPredefinedAppModal = true; return } try { diff --git a/app/javascript/vue/shared/content/attachments/thumbnail.vue b/app/javascript/vue/shared/content/attachments/thumbnail.vue index d114f098b..c34c47b6f 100644 --- a/app/javascript/vue/shared/content/attachments/thumbnail.vue +++ b/app/javascript/vue/shared/content/attachments/thumbnail.vue @@ -112,7 +112,7 @@ @confirm="deleteAttachment" @cancel="deleteModal = false" /> - diff --git a/app/javascript/vue/shared/content/modal/no_predefined_app_modal.vue b/app/javascript/vue/shared/content/modal/no_predefined_app_modal.vue index 342548c29..d3f42149e 100644 --- a/app/javascript/vue/shared/content/modal/no_predefined_app_modal.vue +++ b/app/javascript/vue/shared/content/modal/no_predefined_app_modal.vue @@ -18,22 +18,23 @@
- From 53c9be6f21c08a966e4c81fcdc19d4e3ae219f18 Mon Sep 17 00:00:00 2001 From: Ivan Kljun Date: Thu, 4 Jan 2024 13:59:54 +0100 Subject: [PATCH 035/128] Fix hound suggestions [SCI-9862] --- .../content/attachments/context_menu.vue | 20 ++++-- .../shared/content/attachments/thumbnail.vue | 66 ++++++++++--------- .../content/modal/no_predefined_app_modal.vue | 2 +- 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index 6c60a7d78..b3dfaae5c 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -62,17 +62,23 @@ diff --git a/app/javascript/vue/shared/content/modal/no_predefined_app_modal.vue b/app/javascript/vue/shared/content/modal/no_predefined_app_modal.vue index d3f42149e..0df7e6ceb 100644 --- a/app/javascript/vue/shared/content/modal/no_predefined_app_modal.vue +++ b/app/javascript/vue/shared/content/modal/no_predefined_app_modal.vue @@ -36,5 +36,5 @@ export default { $(this.$refs.modal).modal('hide'); } } -} +}; From 44556f50702be2193ae266ca3e090b4381a3f7bb Mon Sep 17 00:00:00 2001 From: Ivan Kljun Date: Fri, 5 Jan 2024 10:50:39 +0100 Subject: [PATCH 036/128] Add Teleport for modals [SCI-9862] --- .../content/attachments/context_menu.vue | 52 +++++++++---------- .../attachments/mixins/open_locally.js | 13 ++--- config/locales/en.yml | 3 ++ 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index b3dfaae5c..14ff4e8a4 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -30,34 +30,36 @@ @open_ove_editor="openOVEditor(attachment.attributes.urls.open_vector_editor_edit)" @open_marvinjs_editor="openMarvinJsEditor" @open_scinote_editor="openScinoteEditor" - @open_locally="openLocallyButton" + @open_locally="openLocally" @delete="deleteModal = true" @viewMode="changeViewMode" @move="showMoveModal" > - - - - + + @confirm="deleteAttachment" + @cancel="deleteModal = false" + /> + + + + @@ -193,10 +195,6 @@ export default { ); $(this.$refs.marvinjsEditButton).trigger('click'); }, - openLocallyButton() { - this.editAppModal = true; - this.$emit(this.openLocally()); - }, openScinoteEditor() { $(this.$refs.imageEditButton).trigger('click'); } diff --git a/app/javascript/vue/shared/content/attachments/mixins/open_locally.js b/app/javascript/vue/shared/content/attachments/mixins/open_locally.js index 5c8014ca8..fab8ea447 100644 --- a/app/javascript/vue/shared/content/attachments/mixins/open_locally.js +++ b/app/javascript/vue/shared/content/attachments/mixins/open_locally.js @@ -39,20 +39,21 @@ export default { this.localAppName = response.data.application; } catch (error) { - console.error("Error in request: ", error); + console.error('Error in request: ', error); } }, async openLocally() { if (this.localAppName === null) { - this.showNoPredefinedAppModal = true; - return + this.showNoPredefinedAppModal = true; + return; } + + this.editAppModal = true; try { - const response = await axios.get(this.attachment.attributes.urls.open_locally); - const data = response.data; + const { data } = await axios.get(this.attachment.attributes.urls.open_locally); await axios.post(this.attachment.attributes.urls.open_locally_api + '/download', data); } catch (error) { - console.error("Error in request:", error); + console.error('Error in request:', error); } } } diff --git a/config/locales/en.yml b/config/locales/en.yml index 4293c342e..e6eb5ee3e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3566,6 +3566,9 @@ en: body_text_html: "The specified application for accessing the %{file_name} is not preconfigured. To successfully open this file, please set up the appropriate application in your local environment beforehand.

" no_predefined_app: "I understand" set_up_app: "Set up an application to open this file" + edit_launching_application_modal: + title: "Launching application" + description: "%{file_name} will now open in %{application}. Saved changes in %{application} will automatically be synced in SciNote." atwho: no_results: From 245c848c9996acb1d15410a709874ad4d6bd7c41 Mon Sep 17 00:00:00 2001 From: Ivan Kljun Date: Tue, 9 Jan 2024 09:44:00 +0100 Subject: [PATCH 037/128] Change to asset_download_path in Asset Serializer [SCI-9806] --- app/serializers/asset_serializer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/serializers/asset_serializer.rb b/app/serializers/asset_serializer.rb index 764a08f8e..a3049393d 100644 --- a/app/serializers/asset_serializer.rb +++ b/app/serializers/asset_serializer.rb @@ -120,7 +120,7 @@ class AssetSerializer < ActiveModel::Serializer def urls urls = { preview: asset_file_preview_path(object), - download: (rails_blob_path(object.file, disposition: 'attachment') if attached), + download: (asset_download_path(object) if attached), load_asset: load_asset_path(object), asset_file: asset_file_url_path(object), marvin_js: marvin_js_asset_path(object), From 22b7424884514e43e2808c011e9f1019e78d1810 Mon Sep 17 00:00:00 2001 From: Ivan Kljun Date: Thu, 11 Jan 2024 10:41:11 +0100 Subject: [PATCH 038/128] Handle Windows not having an appropriate app for SciNote Edit [SCI-9862] --- .../vue/shared/content/attachments/mixins/open_locally.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/javascript/vue/shared/content/attachments/mixins/open_locally.js b/app/javascript/vue/shared/content/attachments/mixins/open_locally.js index fab8ea447..777b59ff9 100644 --- a/app/javascript/vue/shared/content/attachments/mixins/open_locally.js +++ b/app/javascript/vue/shared/content/attachments/mixins/open_locally.js @@ -37,7 +37,9 @@ export default { `${this.attachment.attributes.urls.open_locally_api}/default-application/${this.attachment.attributes.file_extension}` ); - this.localAppName = response.data.application; + if (response.data.application.toLowerCase() !== 'pick an app') { + this.localAppName = response.data.application; + } } catch (error) { console.error('Error in request: ', error); } From 83a2657bd1500bcb78033b9e9191d0ad0e03fd04 Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Fri, 12 Jan 2024 03:10:11 +0400 Subject: [PATCH 039/128] Improvements of the SciNote Edit option in "Add-ons" [SCI-9962][SCI9760] --- .../packs/vue/scinote_edit_download.js | 9 ++ .../vue/shared/scinote_edit_download.vue | 100 ++++++++++++++++++ .../settings/account/addons/index.html.erb | 70 ++++-------- config/initializers/extends.rb | 2 + config/locales/en.yml | 6 +- config/webpack/webpack.config.js | 1 + 6 files changed, 133 insertions(+), 55 deletions(-) create mode 100644 app/javascript/packs/vue/scinote_edit_download.js create mode 100644 app/javascript/vue/shared/scinote_edit_download.vue diff --git a/app/javascript/packs/vue/scinote_edit_download.js b/app/javascript/packs/vue/scinote_edit_download.js new file mode 100644 index 000000000..ad7eabd15 --- /dev/null +++ b/app/javascript/packs/vue/scinote_edit_download.js @@ -0,0 +1,9 @@ +import { createApp } from 'vue/dist/vue.esm-bundler.js'; +import ScinoteEditDownload from '../../vue/shared/scinote_edit_download.vue'; +import { mountWithTurbolinks } from './helpers/turbolinks.js'; + + +const app = createApp({}); +app.component('ScinoteEditDownload', ScinoteEditDownload); +app.config.globalProperties.i18n = window.I18n; +mountWithTurbolinks(app, '#scinoteEditDownload'); diff --git a/app/javascript/vue/shared/scinote_edit_download.vue b/app/javascript/vue/shared/scinote_edit_download.vue new file mode 100644 index 000000000..f1f7f5d40 --- /dev/null +++ b/app/javascript/vue/shared/scinote_edit_download.vue @@ -0,0 +1,100 @@ + + + \ No newline at end of file diff --git a/app/views/users/settings/account/addons/index.html.erb b/app/views/users/settings/account/addons/index.html.erb index 68f58a22a..9871106d8 100644 --- a/app/views/users/settings/account/addons/index.html.erb +++ b/app/views/users/settings/account/addons/index.html.erb @@ -7,58 +7,6 @@

<%= t('users.settings.account.addons.title') %>

-
-
-
-
-

<%= t('users.settings.account.addons.desktop_app.title') %>

-

- <%= t('users.settings.account.addons..desktop_app.description') %> -


-
- <% if @user_agent =~ /Windows/ %> - <%= link_to '#', - class: 'btn btn-primary new-project-btn', - title: t('users.settings.account.addons.desktop_app.windows_button'), - remote: true do %> - - <% end %> -

<%= t('users.settings.account.addons.desktop_app.version') %> 5.16.5 (24419)

- <% elsif @user_agent =~ /Mac OS/ %> - <%= link_to '#', - class: 'btn btn-primary new-project-btn', - title: t('users.settings.account.addons.desktop_app.macos_button'), - remote: true do %> - - <% end %> -

<%= t('users.settings.account.addons.desktop_app.version') %> 5.16.5 (24419)

- <% else %> -
-
- <%= link_to '#', - class: 'btn btn-primary new-project-btn', - title: t('users.settings.account.addons.desktop_app.macos_button'), - remote: true do %> - - <% end %> -

<%= t('users.settings.account.addons.desktop_app.version') %> 5.16.5 (24419)

-
-
- <%= link_to '#', - class: 'btn btn-primary new-project-btn ml-2', - title: t('users.settings.account.addons.desktop_app.windows_button'), - remote: true do %> - - <% end %> -

<%= t('users.settings.account.addons.desktop_app.version') %> 5.16.5 (24419)

-
-
- <% end %> -
-
-
-
-

<%= t('users.settings.account.addons.scinote_addons') %>

@@ -68,6 +16,22 @@
+
+
+
+
+
+

<%= t('users.settings.account.addons.desktop_app.title') %>

+

+ <%= t('users.settings.account.addons.desktop_app.description') %> +


+
+ +
+
+
+
+

<%= t('users.settings.account.addons.label_printers') %>

@@ -117,3 +81,5 @@
+ +<%= javascript_include_tag "vue_scinote_edit_download", nonce: true %> diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb index 3247672cb..5924070a9 100644 --- a/config/initializers/extends.rb +++ b/config/initializers/extends.rb @@ -605,6 +605,8 @@ class Extends *.nr-data.net www.recaptcha.net/ www.gstatic.com/recaptcha/ + extras.scinote.net + https://www.scinote.net ) if Constants::ASSET_SYNC_URL && EXTERNAL_SERVICES.exclude?(Constants::ASSET_SYNC_URL) diff --git a/config/locales/en.yml b/config/locales/en.yml index e6eb5ee3e..f4e26e0f7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2754,11 +2754,11 @@ en: description: 'Print labels of custom styles and sizes in seconds flat from your PC or Mac via your Zebra printer connected via USB, Internet or LAN.' details: 'Details' desktop_app: - title: 'SciNote File Editor desktop app' - description: 'Download the SciNote File Editor desktop app to automatically edit files using locally installed software' + title: 'SciNote Edit' + description: 'Download the SciNote Edit desktop app to automatically edit files using locally installed software.' macos_button: 'Download for macOS' windows_button: 'Download for Windows' - version: 'Version' + version: 'Version %{version}' label_printer: fluics_printer: "FLUICS Print: Label printers" zebra_printer: 'Zebra label printers' diff --git a/config/webpack/webpack.config.js b/config/webpack/webpack.config.js index 12a4d9e76..42ccf40be 100644 --- a/config/webpack/webpack.config.js +++ b/config/webpack/webpack.config.js @@ -47,6 +47,7 @@ const entryList = { vue_user_preferences: './app/javascript/packs/vue/user_preferences.js', vue_components_manage_stock_value_modal: './app/javascript/packs/vue/manage_stock_value_modal.js', vue_legacy_datetime_picker: './app/javascript/packs/vue/legacy/datetime_picker.js', + vue_scinote_edit_download: './app/javascript/packs/vue/scinote_edit_download.js' } // Engine pack loading based on https://github.com/rails/webpacker/issues/348#issuecomment-635480949 From 5250bade57b909427c549859b41ee29848244600 Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Fri, 12 Jan 2024 03:16:10 +0400 Subject: [PATCH 040/128] hound fix --- .../packs/vue/scinote_edit_download.js | 1 - .../vue/shared/scinote_edit_download.vue | 20 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/javascript/packs/vue/scinote_edit_download.js b/app/javascript/packs/vue/scinote_edit_download.js index ad7eabd15..85640284a 100644 --- a/app/javascript/packs/vue/scinote_edit_download.js +++ b/app/javascript/packs/vue/scinote_edit_download.js @@ -2,7 +2,6 @@ import { createApp } from 'vue/dist/vue.esm-bundler.js'; import ScinoteEditDownload from '../../vue/shared/scinote_edit_download.vue'; import { mountWithTurbolinks } from './helpers/turbolinks.js'; - const app = createApp({}); app.component('ScinoteEditDownload', ScinoteEditDownload); app.config.globalProperties.i18n = window.I18n; diff --git a/app/javascript/vue/shared/scinote_edit_download.vue b/app/javascript/vue/shared/scinote_edit_download.vue index f1f7f5d40..43d82b6ea 100644 --- a/app/javascript/vue/shared/scinote_edit_download.vue +++ b/app/javascript/vue/shared/scinote_edit_download.vue @@ -40,7 +40,9 @@

- {{ i18n.t('users.settings.account.addons.desktop_app.version', { version: this.responseData[0]['version']}) }} + {{ i18n.t('users.settings.account.addons.desktop_app.version', + { version: this.responseData[0]['version']}) + }}

@@ -54,7 +56,9 @@

- {{ i18n.t('users.settings.account.addons.desktop_app.version', { version: this.responseData[1]['version']}) }} + {{ i18n.t('users.settings.account.addons.desktop_app.version', + { version: this.responseData[1]['version']}) + }}

@@ -66,12 +70,12 @@ export default { name: 'ScinoteEditDownload', props: { - data: { type: String, required: true }, + data: { type: String, required: true } }, data() { return { userAgent: this.data, - responseData: {}, + responseData: {} }; }, computed: { @@ -80,7 +84,7 @@ export default { }, isMac() { return /Mac OS/.test(this.userAgent); - }, + } }, created() { window.scinoteEditDownload = this; @@ -94,7 +98,7 @@ export default { $.get('https://extras.scinote.net/scinote-edit/latest.json', (result) => { this.responseData = result; }); - }, - }, + } + } }; - \ No newline at end of file + From aa47cbad950723bf015b95d50a4b16a72db9060c Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Mon, 15 Jan 2024 04:43:00 +0400 Subject: [PATCH 041/128] Make File Checkout feature switchable in settings [SCI-9987] --- .../settings/account/addons/index.html.erb | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/app/views/users/settings/account/addons/index.html.erb b/app/views/users/settings/account/addons/index.html.erb index 9871106d8..daabf6b61 100644 --- a/app/views/users/settings/account/addons/index.html.erb +++ b/app/views/users/settings/account/addons/index.html.erb @@ -17,21 +17,23 @@
-
-
-
-
-

<%= t('users.settings.account.addons.desktop_app.title') %>

-

- <%= t('users.settings.account.addons.desktop_app.description') %> -


-
- + <% if ENV['ASSET_SYNC_URL'] %> +
+
+
+
+

<%= t('users.settings.account.addons.desktop_app.title') %>

+

+ <%= t('users.settings.account.addons.desktop_app.description') %> +


+
+ +
-
+ <% end %>

<%= t('users.settings.account.addons.label_printers') %>

From 4e29b4dab80571f5d03bd4647588fc9fb89acb8a Mon Sep 17 00:00:00 2001 From: Giga Chubinidze Date: Mon, 15 Jan 2024 05:03:18 +0400 Subject: [PATCH 042/128] Add Settings link to Notifications modal [SCI-9986] --- .../vue/navigation/notifications/notifications_flyout.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/javascript/vue/navigation/notifications/notifications_flyout.vue b/app/javascript/vue/navigation/notifications/notifications_flyout.vue index 75ec2213b..833d07777 100644 --- a/app/javascript/vue/navigation/notifications/notifications_flyout.vue +++ b/app/javascript/vue/navigation/notifications/notifications_flyout.vue @@ -2,7 +2,9 @@
{{ i18n.t('nav.notifications.title') }} - + + {{ i18n.t('nav.settings') }} +

From 695c938f22cf5966cd62041cf7d56968c0903118 Mon Sep 17 00:00:00 2001 From: Martin Artnik Date: Mon, 15 Jan 2024 13:44:50 +0100 Subject: [PATCH 043/128] Fix asset thumbnail hover [SCI-9838] --- app/javascript/vue/shared/content/attachments/thumbnail.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/javascript/vue/shared/content/attachments/thumbnail.vue b/app/javascript/vue/shared/content/attachments/thumbnail.vue index 2ec1c0be9..3bbe80b48 100644 --- a/app/javascript/vue/shared/content/attachments/thumbnail.vue +++ b/app/javascript/vue/shared/content/attachments/thumbnail.vue @@ -44,7 +44,7 @@
Date: Mon, 15 Jan 2024 15:16:02 +0100 Subject: [PATCH 044/128] Fix issues with local edit buttons after merging develop [SCI-9841][SCI-9862] --- app/javascript/vue/shared/content/attachments/context_menu.vue | 1 - app/javascript/vue/shared/menu_dropdown.vue | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index 6bb3cb3cf..6a1451837 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -83,7 +83,6 @@ export default { editLaunchingApplicationModal }, mixins: [MoveMixin, OpenLocallyMixin], - components: { deleteAttachmentModal, moveAssetModal, MenuDropdown }, props: { attachment: { type: Object, diff --git a/app/javascript/vue/shared/menu_dropdown.vue b/app/javascript/vue/shared/menu_dropdown.vue index bec8ed99f..cffb6848e 100644 --- a/app/javascript/vue/shared/menu_dropdown.vue +++ b/app/javascript/vue/shared/menu_dropdown.vue @@ -79,6 +79,7 @@ export default { btnClasses: { type: String, default: 'btn btn-light' }, btnText: { type: String, required: false }, btnIcon: { type: String, required: false }, + title: { type: String, default: '' }, caret: { type: Boolean, default: false } }, data() { From 2e1b86f9b2b41e93174becb586fe6f0908d2b6d9 Mon Sep 17 00:00:00 2001 From: Ivan Kljun Date: Thu, 11 Jan 2024 14:41:32 +0100 Subject: [PATCH 045/128] Fix open locally buttons for thumbnail view [SCI-9838] --- .../shared/content/attachments/thumbnail.vue | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/app/javascript/vue/shared/content/attachments/thumbnail.vue b/app/javascript/vue/shared/content/attachments/thumbnail.vue index b4b087b6c..660deaa5f 100644 --- a/app/javascript/vue/shared/content/attachments/thumbnail.vue +++ b/app/javascript/vue/shared/content/attachments/thumbnail.vue @@ -44,8 +44,10 @@
+
- diff --git a/app/javascript/vue/shared/menu_dropdown.vue b/app/javascript/vue/shared/menu_dropdown.vue index cffb6848e..61df17ca9 100644 --- a/app/javascript/vue/shared/menu_dropdown.vue +++ b/app/javascript/vue/shared/menu_dropdown.vue @@ -1,5 +1,5 @@ diff --git a/app/views/shared/file_preview/_content.html.erb b/app/views/shared/file_preview/_content.html.erb index 31fd8e0d8..51130f3e5 100644 --- a/app/views/shared/file_preview/_content.html.erb +++ b/app/views/shared/file_preview/_content.html.erb @@ -27,7 +27,7 @@ <% elsif asset.editable_image? %> - +
+ +
<% end %> <% end %> From 0eb323b2f12ce8d916219122e787e7077c90fe35 Mon Sep 17 00:00:00 2001 From: Ivan Kljun Date: Tue, 23 Jan 2024 11:52:35 +0100 Subject: [PATCH 063/128] Add wrong-version modal for SciNote Edit [SCI-10010] --- .../javascripts/sitewide/constants.js.erb | 2 + .../content/attachments/context_menu.vue | 17 ++++-- .../attachments/mixins/open_locally.js | 16 +++++- .../content/attachments/open_locally_menu.vue | 54 +++++++++++-------- .../shared/content/attachments/thumbnail.vue | 9 +++- .../content/modal/no_predefined_app_modal.vue | 6 +-- .../content/modal/update_version_modal.vue | 54 +++++++++++++++++++ .../vue/shared/scinote_edit_download.vue | 30 +++++++---- .../shared/file_preview/_content.html.erb | 2 +- config/initializers/constants.rb | 4 ++ config/locales/en.yml | 7 ++- 11 files changed, 155 insertions(+), 46 deletions(-) create mode 100644 app/javascript/vue/shared/content/modal/update_version_modal.vue diff --git a/app/assets/javascripts/sitewide/constants.js.erb b/app/assets/javascripts/sitewide/constants.js.erb index 8e37b3abc..2ba7d7fc4 100644 --- a/app/assets/javascripts/sitewide/constants.js.erb +++ b/app/assets/javascripts/sitewide/constants.js.erb @@ -15,4 +15,6 @@ const GLOBAL_CONSTANTS = { FAST_STATUS_POLLING_INTERVAL: <%= Constants::FAST_STATUS_POLLING_INTERVAL %>, SLOW_STATUS_POLLING_INTERVAL: <%= Constants::SLOW_STATUS_POLLING_INTERVAL %>, ASSET_SYNC_URL: '<%= Constants::ASSET_SYNC_URL %>', + MIN_SCINOTE_EDIT_VERSION: '<%= Constants::MIN_SCINOTE_EDIT_VERSION %>', + MAX_SCINOTE_EDIT_VERSION: '<%= Constants::MAX_SCINOTE_EDIT_VERSION %>', }; diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue index 1dd6c0af0..d78379525 100644 --- a/app/javascript/vue/shared/content/attachments/context_menu.vue +++ b/app/javascript/vue/shared/content/attachments/context_menu.vue @@ -57,11 +57,15 @@ :fileName="attachment.attributes.file_name" @confirm="showNoPredefinedAppModal = false" /> +
@@ -72,6 +76,7 @@ import deleteAttachmentModal from './delete_modal.vue'; import editLaunchingApplicationModal from './edit_launching_application_modal.vue'; import moveAssetModal from '../modal/move.vue'; import NoPredefinedAppModal from '../modal/no_predefined_app_modal.vue'; +import UpdateVersionModal from '../modal/update_version_modal.vue'; import MoveMixin from './mixins/move.js'; import OpenLocallyMixin from './mixins/open_locally.js'; import MenuDropdown from '../../menu_dropdown.vue'; @@ -83,6 +88,7 @@ export default { moveAssetModal, MenuDropdown, NoPredefinedAppModal, + UpdateVersionModal, editLaunchingApplicationModal }, mixins: [MoveMixin, OpenLocallyMixin], @@ -98,7 +104,8 @@ export default { viewModeOptions: ['inline', 'thumbnail', 'list'], deleteModal: false, editAppModal: false, - showNoPredefinedAppModal: false + showNoPredefinedAppModal: false, + showUpdateVersionModal: false }; }, computed: { diff --git a/app/javascript/vue/shared/content/attachments/mixins/open_locally.js b/app/javascript/vue/shared/content/attachments/mixins/open_locally.js index 6ce3d06d4..a104e7a7c 100644 --- a/app/javascript/vue/shared/content/attachments/mixins/open_locally.js +++ b/app/javascript/vue/shared/content/attachments/mixins/open_locally.js @@ -1,10 +1,12 @@ import axios from '../../../../../packs/custom_axios.js'; +import { satisfies } from 'compare-versions'; export default { data() { return { localAppName: null, - scinoteEditRunning: false + scinoteEditRunning: false, + scinoteEditVersion: null }; }, computed: { @@ -24,6 +26,7 @@ export default { if (statusResponse.status === 200) { this.scinoteEditRunning = true; + this.scinoteEditVersion = statusResponse.data.version; } else { return; } @@ -40,7 +43,10 @@ export default { } }, async openLocally() { - if (this.localAppName === null) { + if (this.isWrongVersion(this.scinoteEditVersion)) { + this.showUpdateVersionModal = true; + return; + } else if (this.localAppName === null) { this.showNoPredefinedAppModal = true; return; } @@ -52,6 +58,12 @@ export default { } catch (error) { console.error('Error in request:', error); } + }, + isWrongVersion(version) { + const min = GLOBAL_CONSTANTS.MIN_SCINOTE_EDIT_VERSION; + const max = GLOBAL_CONSTANTS.MAX_SCINOTE_EDIT_VERSION; + version = "3.0" + return !satisfies(version, `${min} - ${max}`); } } } diff --git a/app/javascript/vue/shared/content/attachments/open_locally_menu.vue b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue index 43d1498aa..16fe92443 100644 --- a/app/javascript/vue/shared/content/attachments/open_locally_menu.vue +++ b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue @@ -1,21 +1,27 @@ @@ -23,17 +29,21 @@ diff --git a/app/javascript/vue/shared/content/attachments/thumbnail.vue b/app/javascript/vue/shared/content/attachments/thumbnail.vue index 980b1ddab..e8fffed5f 100644 --- a/app/javascript/vue/shared/content/attachments/thumbnail.vue +++ b/app/javascript/vue/shared/content/attachments/thumbnail.vue @@ -145,6 +145,10 @@ :fileName="attachment.attributes.file_name" @confirm="showNoPredefinedAppModal = false" /> +
diff --git a/config/locales/en.yml b/config/locales/en.yml index fd94c30b6..f5a99cefb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3622,7 +3622,7 @@ en: set_up_app: "Set up an application to open this file" update_version_modal: title: "Update required" - body_text_html: "The current version of the SciNote Edit application is no longer supported. To ensure a seamless and secure user experience, we recommend installing to the latest version." + body_text_html: "The current version of the SciNote Edit application is no longer supported. To ensure a seamless and secure user experience, we recommend updating to the latest version." edit_launching_application_modal: title: "Launching application" description: "%{file_name} will now open in %{application}. Saved changes in %{application} will automatically be synced in SciNote." From f2d06a96364122171d489680a59b94779e7feae2 Mon Sep 17 00:00:00 2001 From: Martin Artnik Date: Mon, 12 Feb 2024 12:58:57 +0100 Subject: [PATCH 108/128] Show loader when loading smart annotations [SCI-10087] --- app/assets/javascripts/sitewide/atwho_res.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/assets/javascripts/sitewide/atwho_res.js b/app/assets/javascripts/sitewide/atwho_res.js index 9e3414c72..fe8cb300a 100644 --- a/app/assets/javascripts/sitewide/atwho_res.js +++ b/app/assets/javascripts/sitewide/atwho_res.js @@ -56,11 +56,19 @@ var SmartAnnotation = (function() { at: at, callbacks: { remoteFilter: function(query, callback) { + + // show loader after .25 seconds + var loaderTimeout = setTimeout(function() { + $('.atwho-scroll-container').css({ height: '100px' }); + $('.atwho-scroll-container').html('
'); + }, 250); + var $currentAtWho = $(`.atwho-view[data-at-who-id=${$(field).attr('data-smart-annotation')}]`); var filterType; var params = { query: query }; filterType = FilterTypeEnum[$currentAtWho.find('.tab-pane.active').data('object-type')]; if (!filterType) { + clearTimeout(loaderTimeout); callback([{ name: '' }]); return false; } @@ -73,6 +81,8 @@ var SmartAnnotation = (function() { } } $.getJSON(filterType.dataUrl, params, function(data) { + clearTimeout(loaderTimeout); + localStorage.setItem('smart_annotation_states/teams/' + data.team, JSON.stringify({ tag: filterType.tag, repository: data.repository From ef16651cf38e0801b89a9a717c63ddf8c95acc4f Mon Sep 17 00:00:00 2001 From: Soufiane Date: Mon, 12 Feb 2024 13:44:02 +0100 Subject: [PATCH 109/128] Fix Docx preview marking as ready [SCI-10037] (#7074) --- app/datatables/report_datatable.rb | 2 +- app/jobs/reports/docx_job.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/datatables/report_datatable.rb b/app/datatables/report_datatable.rb index 74f061134..59da7c0de 100644 --- a/app/datatables/report_datatable.rb +++ b/app/datatables/report_datatable.rb @@ -76,7 +76,7 @@ class ReportDatatable < CustomDatatable end def docx_file(report) - docx = document_preview_report_path(report, report_type: :docx) if report.docx_file.attached? + docx = document_preview_report_path(report, report_type: :docx) if report.docx_preview_file.attached? { processing: report.docx_processing?, preview_url: docx, diff --git a/app/jobs/reports/docx_job.rb b/app/jobs/reports/docx_job.rb index 6a07768e9..51043ff37 100644 --- a/app/jobs/reports/docx_job.rb +++ b/app/jobs/reports/docx_job.rb @@ -18,7 +18,6 @@ module Reports Reports::Docx.new(report, docx, user: user, scinote_url: root_url).draw docx.save report.docx_file.attach(io: file, filename: 'report.docx') - report.docx_ready! report_path = Rails.application.routes.url_helpers .reports_path(team: report.team.id, preview_report_id: report.id, preview_type: :docx) @@ -37,6 +36,7 @@ module Reports ) Reports::DocxPreviewJob.perform_now(report.id) + report.docx_ready! ensure I18n.backend.date_format = nil file.close From 230b580ba291c2f47f419fcc296011b9328c85cd Mon Sep 17 00:00:00 2001 From: ajugo Date: Tue, 13 Feb 2024 15:04:30 +0100 Subject: [PATCH 110/128] Improve loading speed of protocol template [SCI-10171] (#7077) --- app/datatables/protocols_datatable.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/app/datatables/protocols_datatable.rb b/app/datatables/protocols_datatable.rb index 5ce0b5075..711b40eff 100644 --- a/app/datatables/protocols_datatable.rb +++ b/app/datatables/protocols_datatable.rb @@ -146,7 +146,22 @@ class ProtocolsDatatable < CustomDatatable end def get_raw_records_base - records = Protocol.latest_available_versions(@team) + team_protocols = Protocol.where(team: @team) + original_without_versions = team_protocols + .left_outer_joins(:published_versions) + .in_repository_published_original + .where(published_versions: { id: nil }) + .select(:id) + published_versions = team_protocols + .in_repository_published_version + .order(:parent_id, version_number: :desc) + .select('DISTINCT ON (parent_id) id') + new_drafts = team_protocols + .where(protocol_type: Protocol.protocol_types[:in_repository_draft], parent_id: nil) + .select(:id) + + records = Protocol.where('protocols.id IN (?) OR protocols.id IN (?) OR protocols.id IN (?)', + original_without_versions, published_versions, new_drafts) records = @type == :archived ? records.archived : records.active From daa5280521dd2b460ffdabcd3441c226e52575a8 Mon Sep 17 00:00:00 2001 From: Soufiane Date: Tue, 13 Feb 2024 15:04:57 +0100 Subject: [PATCH 111/128] Update the navigator tree on state change and owner assignement permission change [SCI-10123] (#7081) --- .../javascripts/access_permissions/user_assignments.js | 8 ++++++++ app/javascript/vue/navigation/navigator_item.vue | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/app/assets/javascripts/access_permissions/user_assignments.js b/app/assets/javascripts/access_permissions/user_assignments.js index a4d6bda35..fc9348ca0 100644 --- a/app/assets/javascripts/access_permissions/user_assignments.js +++ b/app/assets/javascripts/access_permissions/user_assignments.js @@ -45,6 +45,10 @@ $(document).on('ajax:success', 'form#new-user-assignment-form', function(_e, data) { $('#user_assignments_modal').replaceWith($(data.html).find('#user_assignments_modal')); HelperModule.flashAlertMsg(data.flash, 'success'); + + if (window.actionToolbarComponent?.reloadCallback) { + window.actionToolbarComponent.reloadCallback(); + } }); $(document).on('ajax:error', 'form#new-user-assignment-form', function(_e, data) { @@ -60,6 +64,10 @@ if (data.flash) { HelperModule.flashAlertMsg(data.flash, 'success'); } + + if (window.actionToolbarComponent?.reloadCallback) { + window.actionToolbarComponent.reloadCallback(); + } }); $(document).on('click', '.user-assignment-dropdown .user-role-selector', function() { diff --git a/app/javascript/vue/navigation/navigator_item.vue b/app/javascript/vue/navigation/navigator_item.vue index 4c7c90fa4..7d31232d8 100644 --- a/app/javascript/vue/navigation/navigator_item.vue +++ b/app/javascript/vue/navigation/navigator_item.vue @@ -123,6 +123,11 @@ export default { } else if (this.childrenLoaded) { this.item.has_children = false; } + }, + archived() { + if (this.childrenExpanded) { + this.loadChildren(); + } } }, methods: { From 7fe6aae84360f630d2cbcbf99a27f478dba7c630 Mon Sep 17 00:00:00 2001 From: ajugo Date: Tue, 13 Feb 2024 15:05:34 +0100 Subject: [PATCH 112/128] Fix consumption check for full view repository [SCI-10184] (#7082) --- app/controllers/my_module_repositories_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/my_module_repositories_controller.rb b/app/controllers/my_module_repositories_controller.rb index e32d8cf4d..b2a201544 100644 --- a/app/controllers/my_module_repositories_controller.rb +++ b/app/controllers/my_module_repositories_controller.rb @@ -130,7 +130,7 @@ class MyModuleRepositoriesController < ApplicationController render json: { html: render_to_string( partial: 'my_modules/repositories/full_view_table', - locals: { include_stock_consumption: params[:include_stock_consumption] } + locals: { include_stock_consumption: params[:include_stock_consumption] == 'true' } ) } end From b14912e70e5bd5190a5068782e558923ec42bba3 Mon Sep 17 00:00:00 2001 From: ajugo Date: Thu, 15 Feb 2024 11:33:23 +0100 Subject: [PATCH 113/128] Fix assigned repository export in project export [SCI-10193] (#7087) --- app/models/report.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/report.rb b/app/models/report.rb index 38cc222d0..5f5ff7fb7 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -131,6 +131,7 @@ class Report < ApplicationRecord report.user = current_user report.team = current_team report.last_modified_by = current_user + report.settings[:task][:repositories] = content['repositories'] ReportActions::ReportContent.new(report, content, {}, current_user).save_with_content report end From e026f2b1356f49cf4f42ad7df9188b3b33184be0 Mon Sep 17 00:00:00 2001 From: ajugo Date: Thu, 15 Feb 2024 13:00:09 +0100 Subject: [PATCH 114/128] Add check for showing consumption column [SCI-10185] (#7085) --- app/models/my_module.rb | 14 ++++++++----- app/models/repository_base.rb | 4 ++++ .../repositories/_full_view_sidebar.html.erb | 2 +- .../_full_view_snapshot_table.html.erb | 20 ++++++++++--------- .../repositories/_repositories_list.html.erb | 8 ++++---- .../my_modules/_repositories_list.html.erb | 4 ++-- 6 files changed, 31 insertions(+), 21 deletions(-) diff --git a/app/models/my_module.rb b/app/models/my_module.rb index d6f8e1b28..266582b12 100644 --- a/app/models/my_module.rb +++ b/app/models/my_module.rb @@ -338,7 +338,7 @@ class MyModule < ApplicationRecord ] data = [] rows = repository.assigned_rows(self).includes(:created_by).order(created_at: order) - if repository.has_stock_management? + if repository.has_stock_management? && repository.has_stock_consumption? headers.push(I18n.t('repositories.table.row_consumption')) rows = rows.left_joins(my_module_repository_rows: :repository_stock_unit_item) .select( @@ -352,7 +352,7 @@ class MyModule < ApplicationRecord row_json << (row.archived ? "#{row.name} [#{I18n.t('general.archived')}]" : row.name) row_json << I18n.l(row.created_at, format: :full) row_json << row.created_by.full_name - if repository.has_stock_management? + if repository.has_stock_management? && repository.has_stock_consumption? if repository.is_a?(RepositorySnapshot) consumed_stock = row.repository_stock_consumption_cell&.value&.formatted row_json << (consumed_stock || 0) @@ -378,11 +378,15 @@ class MyModule < ApplicationRecord repository.repository_columns.order(:id).each do |column| if column.data_type == 'RepositoryStockValue' - headers.push(I18n.t('repositories.table.row_consumption')) - else + if repository.has_stock_consumption? + headers.push(I18n.t('repositories.table.row_consumption')) + custom_columns.push(column.id) + end + elsif column.data_type != 'RepositoryStockConsumptionValue' && + !(repository.is_a?(RepositorySnapshot) && column.data_type == 'RepositoryStockConsumptionValue') headers.push(column.name) + custom_columns.push(column.id) end - custom_columns.push(column.id) end records = repository.assigned_rows(self) diff --git a/app/models/repository_base.rb b/app/models/repository_base.rb index e260c1bc8..dab25f492 100644 --- a/app/models/repository_base.rb +++ b/app/models/repository_base.rb @@ -43,6 +43,10 @@ class RepositoryBase < ApplicationRecord self.class.stock_management_enabled? && repository_columns.stock_type.exists? end + def has_stock_consumption? + true + end + def cell_preload_includes cell_includes = [] repository_columns.pluck(:data_type).each do |data_type| diff --git a/app/views/my_modules/repositories/_full_view_sidebar.html.erb b/app/views/my_modules/repositories/_full_view_sidebar.html.erb index da91bb695..a5d85b56c 100644 --- a/app/views/my_modules/repositories/_full_view_sidebar.html.erb +++ b/app/views/my_modules/repositories/_full_view_sidebar.html.erb @@ -10,7 +10,7 @@

<%= t('my_modules.repository.snapshots.full_view.live') %> diff --git a/app/views/my_modules/repositories/_full_view_snapshot_table.html.erb b/app/views/my_modules/repositories/_full_view_snapshot_table.html.erb index d18650e48..c60472cfd 100644 --- a/app/views/my_modules/repositories/_full_view_snapshot_table.html.erb +++ b/app/views/my_modules/repositories/_full_view_snapshot_table.html.erb @@ -19,15 +19,17 @@ <%= t("repositories.table.added_on") %> <%= t("repositories.table.added_by") %> <% @repository_snapshot.repository_columns.order(:parent_id).each do |column| %> - - <%= "data-metadata-#{k}=#{v}" %> - <% end %> - > - <%= display_tooltip(column.name) %> - + <% if column.data_type != 'RepositoryStockConsumptionValue' || @repository_snapshot.has_stock_consumption? %> + + <%= "data-metadata-#{k}=#{v}" %> + <% end %> + > + <%= display_tooltip(column.name) %> + + <% end %> <% end %> diff --git a/app/views/my_modules/repositories/_repositories_list.html.erb b/app/views/my_modules/repositories/_repositories_list.html.erb index 1c66ee542..cb6d3c203 100644 --- a/app/views/my_modules/repositories/_repositories_list.html.erb +++ b/app/views/my_modules/repositories/_repositories_list.html.erb @@ -16,7 +16,7 @@ <% end %>
-
@@ -28,12 +28,12 @@ data-name-column-id="<%= assigned_repository_simple_view_name_column_id(repository) %>" > + data-stock-management="<%= repository.has_stock_management? && repository.has_stock_consumption? %>" + data-stock-consumption-editable="<%= can_update_my_module_stock_consumption?(@my_module) && repository.has_stock_consumption? %>"> - <% if repository.has_stock_management? %> + <% if repository.has_stock_management? && repository.has_stock_consumption? %> <% end %> diff --git a/app/views/shareable_links/my_modules/_repositories_list.html.erb b/app/views/shareable_links/my_modules/_repositories_list.html.erb index 4cd4d89cc..8a87b23cc 100644 --- a/app/views/shareable_links/my_modules/_repositories_list.html.erb +++ b/app/views/shareable_links/my_modules/_repositories_list.html.erb @@ -25,12 +25,12 @@ data-name-column-id="<%= assigned_repository_simple_view_name_column_id(repository) %>" > - <% if repository.has_stock_management? %> + <% if repository.has_stock_management? && repository.has_stock_consumption? %> <% end %> From 87eeaab08d086b85bcfe05996003b6448eb0e250 Mon Sep 17 00:00:00 2001 From: Martin Artnik Date: Thu, 15 Feb 2024 13:15:05 +0100 Subject: [PATCH 115/128] Fix WOPI editing not opening in new tab [SCI-10224] --- .../vue/shared/content/attachments/open_locally_menu.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/vue/shared/content/attachments/open_locally_menu.vue b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue index 61341e181..efc3f45f8 100644 --- a/app/javascript/vue/shared/content/attachments/open_locally_menu.vue +++ b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue @@ -19,7 +19,7 @@ @open-locally="openLocally" @open-image-editor="openImageEditor" > - + {{ menu[0].text }} From 82d9996f22cb5493b0d69c02e57d5931f9a2c645 Mon Sep 17 00:00:00 2001 From: Gregor Lasnibat <143816208+lasniscinote@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:05:31 +0100 Subject: [PATCH 116/128] (fix) CSS for Quartzy [SCI-10159-core] (#7090) --- app/javascript/vue/shared/wizard_modal.vue | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/javascript/vue/shared/wizard_modal.vue b/app/javascript/vue/shared/wizard_modal.vue index cdc2b4ee3..a69b6e132 100644 --- a/app/javascript/vue/shared/wizard_modal.vue +++ b/app/javascript/vue/shared/wizard_modal.vue @@ -3,7 +3,9 @@
<%= t("repositories.table.row_name") %><%= repository.repository_stock_column.name %> <%= t("repositories.table.row_consumption") %>