mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-09-20 14:45:56 +08:00
Add BioEddie integration [SCI-5654][SCI-5657][SCI-5658][SCI-5670] (#3391)
* Add backend for bioeddie [SCI-5654] * Add modal for bioeddie [SCI-5654] * Add bio eddie editor to steps and results [SCI-5654] * Fix markup and code styling
This commit is contained in:
parent
b7513c6d5f
commit
786e74e4de
BIN
app/assets/images/icon_small/bio_eddie.png
Normal file
BIN
app/assets/images/icon_small/bio_eddie.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 986 B |
BIN
app/assets/images/icon_small/bio_eddie_white.png
Normal file
BIN
app/assets/images/icon_small/bio_eddie_white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
152
app/assets/javascripts/sitewide/bio_eddie.js
Normal file
152
app/assets/javascripts/sitewide/bio_eddie.js
Normal file
|
@ -0,0 +1,152 @@
|
|||
/* global HelperModule I18n */
|
||||
var bioEddieEditor = (function() {
|
||||
var BIO_EDDIE;
|
||||
var CHEMAXON;
|
||||
var bioEddieIframe;
|
||||
var bioEddieModal;
|
||||
|
||||
function importMolecule() {
|
||||
var monomerModel = BIO_EDDIE.getMonomerModel();
|
||||
var monomerImporter = new CHEMAXON.HelmImportModule();
|
||||
var molecule = bioEddieModal.data('molecule') || '';
|
||||
monomerImporter.import(molecule, monomerModel)
|
||||
.then(builder => BIO_EDDIE.setModel(builder.graphStoreData));
|
||||
}
|
||||
|
||||
function loadBioEddie() {
|
||||
BIO_EDDIE = bioEddieIframe.contentWindow.bioEddieEditor;
|
||||
CHEMAXON = bioEddieIframe.contentWindow.chemaxon;
|
||||
|
||||
if (typeof BIO_EDDIE === 'undefined' || typeof CHEMAXON === 'undefined') {
|
||||
setTimeout(function() {
|
||||
loadBioEddie();
|
||||
}, 2000);
|
||||
} else {
|
||||
importMolecule();
|
||||
}
|
||||
}
|
||||
|
||||
function initIframe() {
|
||||
if (typeof BIO_EDDIE === 'undefined' || typeof CHEMAXON === 'undefined') {
|
||||
bioEddieIframe.src = bioEddieIframe.dataset.src;
|
||||
loadBioEddie();
|
||||
} else {
|
||||
importMolecule();
|
||||
}
|
||||
}
|
||||
|
||||
function saveMolecule(svg, structure) {
|
||||
var moleculeName = bioEddieModal.find('.file-name input').val();
|
||||
$.post(bioEddieModal.data('create-url'), {
|
||||
description: structure,
|
||||
object_id: bioEddieModal.data('object_id'),
|
||||
object_type: bioEddieModal.data('object_type'),
|
||||
name: moleculeName,
|
||||
image: svg
|
||||
}, function(result) {
|
||||
var newAsset = $(result.html);
|
||||
if (bioEddieModal.data('object_type') === 'Step') {
|
||||
newAsset.find('.file-preview-link').css('top', '-300px');
|
||||
newAsset.addClass('new').prependTo($(bioEddieModal.data('assets_container')));
|
||||
setTimeout(function() {
|
||||
newAsset.find('.file-preview-link').css('top', '0px');
|
||||
}, 200);
|
||||
bioEddieModal.modal('hide');
|
||||
} else if (bioEddieModal.data('object_type') === 'Result') {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateMolecule(svg, structure) {
|
||||
var moleculeName = bioEddieModal.find('.file-name input').val();
|
||||
$.ajax({
|
||||
url: bioEddieModal.data('update-url'),
|
||||
data: {
|
||||
description: structure,
|
||||
name: moleculeName,
|
||||
image: svg
|
||||
},
|
||||
dataType: 'json',
|
||||
type: 'PUT',
|
||||
success: function(json) {
|
||||
$('#modal_link' + json.id + ' img').attr('src', json.url);
|
||||
$('#modal_link' + json.id + ' .attachment-label').html(json.file_name);
|
||||
bioEddieModal.modal('hide');
|
||||
},
|
||||
error: function(response) {
|
||||
if (response.status === 403) {
|
||||
HelperModule.flashAlertMsg(I18n.t('general.no_permissions'), 'danger');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function generateImage(structure) {
|
||||
var imageGenerator = new CHEMAXON.ImageGenerator();
|
||||
var emptySVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
imageGenerator.generateSVGFromHelm(emptySVG, structure)
|
||||
.then(svg => {
|
||||
if (bioEddieModal.data('edit-mode')) {
|
||||
updateMolecule(svg, structure);
|
||||
} else {
|
||||
saveMolecule(svg, structure);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('turbolinks:load', function() {
|
||||
bioEddieIframe = document.getElementById('bioEddieIframe');
|
||||
bioEddieModal = $('#bioEddieModal');
|
||||
|
||||
bioEddieModal.on('shown.bs.modal', function() {
|
||||
initIframe();
|
||||
});
|
||||
|
||||
bioEddieModal.on('click', '.file-save-link', function() {
|
||||
var model = BIO_EDDIE.getModel();
|
||||
var monomerModel = BIO_EDDIE.getMonomerModel();
|
||||
var monomerExporter = new CHEMAXON.Helm2ExportModule();
|
||||
|
||||
monomerExporter.export(model, monomerModel)
|
||||
.then(structure => generateImage(structure));
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
open_new: (objectId, objectType, container) => {
|
||||
bioEddieModal.data('object_id', objectId);
|
||||
bioEddieModal.data('object_type', objectType);
|
||||
bioEddieModal.data('assets_container', container);
|
||||
bioEddieModal.find('.file-name input').val('');
|
||||
bioEddieModal.modal('show');
|
||||
},
|
||||
|
||||
open_edit: (name, molecule, updateUrl) => {
|
||||
bioEddieModal.data('edit-mode', true);
|
||||
bioEddieModal.data('molecule', molecule);
|
||||
bioEddieModal.data('update-url', updateUrl);
|
||||
bioEddieModal.find('.file-name input').val(name);
|
||||
bioEddieModal.modal('show');
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
(function() {
|
||||
$(document).on('click', '.new-bio-eddie-upload-button', function() {
|
||||
bioEddieEditor.open_new(
|
||||
this.dataset.objectId,
|
||||
this.dataset.objectType,
|
||||
this.dataset.assetsContainer
|
||||
);
|
||||
});
|
||||
|
||||
$(document).on('click', '.bio-eddie-edit-button', function() {
|
||||
$('#filePreviewModal').modal('hide');
|
||||
bioEddieEditor.open_edit(
|
||||
this.dataset.moleculeName,
|
||||
this.dataset.moleculeDescription,
|
||||
this.dataset.updateUrl
|
||||
);
|
||||
});
|
||||
}());
|
75
app/assets/stylesheets/bio_eddie.scss
Normal file
75
app/assets/stylesheets/bio_eddie.scss
Normal file
|
@ -0,0 +1,75 @@
|
|||
// scss-lint:disable SelectorDepth
|
||||
// scss-lint:disable NestingDepth
|
||||
// scss-lint:disable SelectorFormat
|
||||
// scss-lint:disable ImportantRule
|
||||
// scss-lint:disable IdSelector
|
||||
|
||||
@import "constants";
|
||||
@import "mixins";
|
||||
|
||||
// MarvinJs modal
|
||||
.modal-bio-eddie {
|
||||
background: transparent;
|
||||
font-size: $font-size-base;
|
||||
padding: 0 !important;
|
||||
|
||||
.modal-dialog {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
background: $color-white;
|
||||
display: flex;
|
||||
height: 60px;
|
||||
line-height: 40px;
|
||||
padding: 10px 15px;
|
||||
text-align: center;
|
||||
|
||||
.file-save-link {
|
||||
flex-shrink: 0;
|
||||
margin: 0 20px 0 0;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
float: left;
|
||||
margin-right: auto;
|
||||
|
||||
input {
|
||||
border-radius: 5px;
|
||||
box-shadow: none;
|
||||
color: $color-black;
|
||||
height: 40px;
|
||||
margin-left: 5px;
|
||||
outline: 0;
|
||||
padding: 5px 10px;
|
||||
position: relative;
|
||||
width: 350px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
height: calc(100% - 60px);
|
||||
padding: 0;
|
||||
|
||||
iframe {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -61,6 +61,34 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.bio_eddie {
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
border-radius: 1em 0 0 1em;
|
||||
bottom: 1em;
|
||||
content: "";
|
||||
display: block;
|
||||
height: 2em;
|
||||
line-height: 2em;
|
||||
position: absolute;
|
||||
right: -1em;
|
||||
width: 2.25em;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background: $bio-eddie-color;
|
||||
}
|
||||
|
||||
&::after {
|
||||
background-image: url("/images/icon_small/bio_eddie_white.png");
|
||||
background-repeat: no-repeat;
|
||||
height: 1.85em;
|
||||
right: -1.15em;
|
||||
width: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.fas {
|
||||
font-size: 100px;
|
||||
line-height: 160px;
|
||||
|
|
|
@ -41,6 +41,9 @@ $office-ms-powerpoint: #d24726;
|
|||
// MarvinJS color:
|
||||
$marvinjs-color: #29999c;
|
||||
|
||||
// BioEddie color:
|
||||
$bio-eddie-color: #ffa000;
|
||||
|
||||
$pdf-color: #f40f02;
|
||||
|
||||
// Don't use them
|
||||
|
|
99
app/controllers/bio_eddie_assets_controller.rb
Normal file
99
app/controllers/bio_eddie_assets_controller.rb
Normal file
|
@ -0,0 +1,99 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BioEddieAssetsController < ApplicationController
|
||||
include ActiveStorage::SetCurrent
|
||||
|
||||
before_action :load_vars, except: :create
|
||||
before_action :load_create_vars, only: :create
|
||||
|
||||
before_action :check_read_permission
|
||||
before_action :check_edit_permission, only: %i(update create start_editing)
|
||||
|
||||
def create
|
||||
asset = BioEddieService.create_molecule(bio_eddie_params, current_user, current_team)
|
||||
|
||||
if asset && bio_eddie_params[:object_type] == 'Step'
|
||||
render json: {
|
||||
html: render_to_string(partial: 'assets/asset.html.erb', locals: {
|
||||
asset: asset,
|
||||
gallery_view_id: bio_eddie_params[:object_id]
|
||||
})
|
||||
}
|
||||
elsif asset && bio_eddie_params[:object_type] == 'Result'
|
||||
render json: { status: 'created' }, status: :ok
|
||||
else
|
||||
render json: asset.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
asset = BioEddieService.update_molecule(bio_eddie_params, current_user, current_team)
|
||||
|
||||
if asset
|
||||
render json: { url: rails_representation_url(asset.medium_preview),
|
||||
id: asset.id,
|
||||
file_name: asset.blob.metadata['name'] }
|
||||
else
|
||||
render json: { error: t('bio_eddie.no_molecules_found') }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def start_editing
|
||||
# Activity here
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_vars
|
||||
@asset = current_team.assets.find_by(id: params[:id])
|
||||
return render_404 unless @asset
|
||||
|
||||
@assoc = @asset.step || @asset.result
|
||||
|
||||
case @assoc
|
||||
when Step
|
||||
@protocol = @assoc.protocol
|
||||
when Result
|
||||
@my_module = @assoc.my_module
|
||||
end
|
||||
end
|
||||
|
||||
def load_create_vars
|
||||
case bio_eddie_params[:object_type]
|
||||
when 'Step'
|
||||
@assoc = Step.find_by(id: bio_eddie_params[:object_id])
|
||||
@protocol = @assoc.protocol
|
||||
when 'Result'
|
||||
@assoc = MyModule.find_by(id: bio_eddie_params[:object_id])
|
||||
@my_module = @assoc
|
||||
end
|
||||
end
|
||||
|
||||
def check_read_permission
|
||||
case @assoc
|
||||
when Step
|
||||
return render_403 unless can_read_protocol_in_module?(@protocol) ||
|
||||
can_read_protocol_in_repository?(@protocol)
|
||||
when Result, MyModule
|
||||
return render_403 unless can_read_experiment?(@my_module.experiment)
|
||||
else
|
||||
render_403
|
||||
end
|
||||
end
|
||||
|
||||
def check_edit_permission
|
||||
case @assoc
|
||||
when Step
|
||||
return render_403 unless can_manage_protocol_in_module?(@protocol) ||
|
||||
can_manage_protocol_in_repository?(@protocol)
|
||||
when Result, MyModule
|
||||
return render_403 unless can_manage_module?(@my_module)
|
||||
else
|
||||
render_403
|
||||
end
|
||||
end
|
||||
|
||||
def bio_eddie_params
|
||||
params.permit(:id, :description, :object_id, :object_type, :name, :image)
|
||||
end
|
||||
end
|
78
app/services/bio_eddie_service.rb
Normal file
78
app/services/bio_eddie_service.rb
Normal file
|
@ -0,0 +1,78 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BioEddieService
|
||||
class << self
|
||||
def url
|
||||
ApplicationSettings.instance.values['bio_eddie_url']
|
||||
end
|
||||
|
||||
def enabled?
|
||||
url.present?
|
||||
end
|
||||
|
||||
def create_molecule(params, current_user, current_team)
|
||||
file = image_io(params)
|
||||
|
||||
asset = Asset.new(created_by: current_user,
|
||||
last_modified_by: current_user,
|
||||
team_id: current_team.id)
|
||||
attach_file(asset.file, file, params)
|
||||
asset.save!
|
||||
asset.post_process_file(current_team)
|
||||
connect_asset(asset, params, current_user)
|
||||
end
|
||||
|
||||
def update_molecule(params, _current_user, current_team)
|
||||
asset = current_team.assets.find(params[:id])
|
||||
attachment = asset&.file
|
||||
|
||||
return unless attachment
|
||||
|
||||
file = image_io(params)
|
||||
attach_file(attachment, file, params)
|
||||
asset
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def connect_asset(asset, params, current_user)
|
||||
case params[:object_type]
|
||||
when 'Step'
|
||||
object = params[:object_type].constantize.find(params[:object_id])
|
||||
asset.update!(view_mode: object.assets_view_mode)
|
||||
object.assets << asset
|
||||
when 'Result'
|
||||
my_module = MyModule.find_by(id: params[:object_id])
|
||||
return unless my_module
|
||||
|
||||
Result.create(user: current_user,
|
||||
my_module: my_module,
|
||||
name: prepare_name(params[:name]),
|
||||
asset: asset,
|
||||
last_modified_by: current_user)
|
||||
end
|
||||
asset
|
||||
end
|
||||
|
||||
def image_io(params)
|
||||
StringIO.new(params[:image])
|
||||
end
|
||||
|
||||
def attach_file(attachment, file, params)
|
||||
attachment.attach(
|
||||
io: file,
|
||||
filename: "#{prepare_name(params[:name])}.svg",
|
||||
content_type: 'image/svg+xml',
|
||||
metadata: {
|
||||
name: prepare_name(params[:name]),
|
||||
description: params[:description],
|
||||
asset_type: 'bio_eddie'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def prepare_name(sketch_name)
|
||||
sketch_name.presence || I18n.t('bio_eddie.new_molecule')
|
||||
end
|
||||
end
|
||||
end
|
11
app/views/assets/bio_eddie/_create_bio_eddie_li.html.erb
Normal file
11
app/views/assets/bio_eddie/_create_bio_eddie_li.html.erb
Normal file
|
@ -0,0 +1,11 @@
|
|||
<li>
|
||||
<a
|
||||
class="new-bio-eddie-upload-button"
|
||||
data-object-id="<%= element_id %>"
|
||||
data-object-type="<%= element_type %>"
|
||||
data-assets-container="<%= assets_container %>"
|
||||
>
|
||||
<%= image_tag 'icon_small/bio_eddie.png' %>
|
||||
<%= t('bio_eddie.new_button') %>
|
||||
</a>
|
||||
</li>
|
|
@ -29,6 +29,8 @@
|
|||
</li>
|
||||
<%= render partial: '/assets/marvinjs/create_marvin_sketch_li',
|
||||
locals: { element_id: @my_module.id, element_type: 'Result', sketch_container: "#results[data-module-id=#{@my_module.id}]" } %>
|
||||
<%= render partial: '/assets/bio_eddie/create_bio_eddie_li.html.erb',
|
||||
locals: { element_id: @my_module.id, element_type: 'Result', assets_container:"#results[data-module-id=#{@my_module.id}]" } %>
|
||||
<%= render partial: "assets/wopi/create_wopi_file_li",
|
||||
locals: { element_id: @my_module.id, element_type: 'Result' } %>
|
||||
</ul>
|
||||
|
@ -69,6 +71,9 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<%= render partial: "shared/bio_eddie_modal.html.erb" %>
|
||||
|
||||
|
||||
<%= javascript_include_tag "handsontable.full" %>
|
||||
|
||||
<!-- Libraries for formulas -->
|
||||
|
|
|
@ -34,3 +34,5 @@
|
|||
|
||||
<%= javascript_include_tag "assets/wopi/create_wopi_file" %>
|
||||
<%= javascript_include_tag "protocols/steps" %>
|
||||
|
||||
<%= render partial: "shared/bio_eddie_modal.html.erb" %>
|
||||
|
|
33
app/views/shared/_bio_eddie_modal.html.erb
Normal file
33
app/views/shared/_bio_eddie_modal.html.erb
Normal file
|
@ -0,0 +1,33 @@
|
|||
<% if BioEddieService.enabled? %>
|
||||
<div id="bioEddieModal"
|
||||
class="modal modal-bio-eddie"
|
||||
role="dialog"
|
||||
aria-labelledby="bioEddieModal"
|
||||
aria-hidden="true"
|
||||
data-create-url="<%= bio_eddie_assets_path %>"
|
||||
data-backdrop="static"
|
||||
data-keyboard="false">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<span class="file-name">
|
||||
<div class="sci-input-container ">
|
||||
<%= text_field_tag :molecule_name, '', placeholder: t('bio_eddie.molecule_name_placeholder'), class: 'sci-input-field' %>
|
||||
</div>
|
||||
</span>
|
||||
<button class="file-save-link btn btn-light">
|
||||
<i class="fas fa-save"></i>
|
||||
<%= t('SaveClose')%>
|
||||
</button>
|
||||
<button class="preview-close btn btn-light icon-btn" data-dismiss="modal">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<iframe id="bioEddieIframe" data-src="<%= BioEddieService.url %>/index.html" frameBorder="0" ></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
@ -21,6 +21,16 @@
|
|||
<span class="fas fa-pencil-alt"></span>
|
||||
<%= t('assets.file_preview.edit_in_marvinjs') %>
|
||||
</button>
|
||||
<% elsif asset.file.metadata[:asset_type] == 'bio_eddie' %>
|
||||
<button class="btn btn-light bio-eddie-edit-button"
|
||||
data-molecule-id="<%= asset.id %>"
|
||||
data-update-url="<%= bio_eddie_asset_path(asset) %>"
|
||||
data-molecule-name="<%= asset.file.metadata[:name] %>"
|
||||
data-molecule-description="<%= asset.file.metadata[:description] %>"
|
||||
>
|
||||
<span class="fas fa-pencil-alt"></span>
|
||||
<%= t('assets.file_preview.edit_in_bio_eddie') %>
|
||||
</button>
|
||||
<% elsif asset.editable_image? %>
|
||||
<button class="btn btn-light image-edit-button"
|
||||
data-image-id="<%= asset.id %>"
|
||||
|
|
|
@ -24,10 +24,11 @@
|
|||
data-step-id="<%= step.id %>"
|
||||
data-state-save-url="<%= update_view_state_step_path(step.id) %>">
|
||||
<li class="divider-label"><%= t("protocols.steps.attachments.add") %></li>
|
||||
<li>
|
||||
<%= render partial: '/assets/marvinjs/create_marvin_sketch_li.html.erb',
|
||||
locals: { element_id: step.id, element_type: 'Step', sketch_container: ".attachments[data-step-id=#{step.id}]" } %>
|
||||
</li>
|
||||
<%= render partial: '/assets/marvinjs/create_marvin_sketch_li.html.erb',
|
||||
locals: { element_id: step.id, element_type: 'Step', sketch_container: ".attachments[data-step-id=#{step.id}]" } %>
|
||||
<%= render partial: '/assets/bio_eddie/create_bio_eddie_li.html.erb',
|
||||
locals: { element_id: step.id, element_type: 'Step', assets_container: ".attachments[data-step-id=#{step.id}]" } %>
|
||||
|
||||
<li>
|
||||
<%= render partial: '/assets/wopi/create_wopi_file_li.html.erb',
|
||||
locals: { element_id: step.id, element_type: 'Step' } %>
|
||||
|
|
|
@ -2396,6 +2396,7 @@ en:
|
|||
file_preview:
|
||||
edit_in_scinote: "Edit in SciNote"
|
||||
edit_in_marvinjs: "Edit in Marvin JS"
|
||||
edit_in_bio_eddie: "Edit in BioEddie"
|
||||
context_menu:
|
||||
set_view_size: "SET VIEW SIZE"
|
||||
delete: "Delete file"
|
||||
|
@ -2635,6 +2636,12 @@ en:
|
|||
invite_users:
|
||||
permission_error: "You don't have permission to invite additional users to this team. Contact its administrator/s."
|
||||
|
||||
bio_eddie:
|
||||
new_molecule: "New Molecule"
|
||||
new_button: "Create Biomolecule"
|
||||
molecule_name_placeholder: "Click here to enter Molecule name"
|
||||
no_molecules_found: "No Molecules Found"
|
||||
|
||||
marvinjs:
|
||||
new_sketch: "New Chemical Drawing"
|
||||
new_button: "Create Chemical Drawing"
|
||||
|
@ -2642,6 +2649,7 @@ en:
|
|||
structure_placeholder: "Click here to enter Chemical Drawing name"
|
||||
modal_name_title: "Chemical Drawing name:"
|
||||
checmical_drawing: "Chemical drawings"
|
||||
no_sketches_found: "No Sketches Found"
|
||||
|
||||
pdf_preview:
|
||||
fit_to_screen: 'Fit to screen'
|
||||
|
|
|
@ -773,6 +773,12 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :bio_eddie_assets, only: %i(create update) do
|
||||
member do
|
||||
post :start_editing
|
||||
end
|
||||
end
|
||||
|
||||
post 'global_activities', to: 'global_activities#index'
|
||||
|
||||
constraints WopiSubdomain do
|
||||
|
|
BIN
public/images/icon_small/bio_eddie_white.png
Normal file
BIN
public/images/icon_small/bio_eddie_white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
Loading…
Reference in a new issue