Merge branch 'develop' into features/inventory-item-card-edit

This commit is contained in:
Oleksii Kriuchykhin 2023-11-15 10:58:42 +01:00
commit 3bc7edc7f7
74 changed files with 693 additions and 303 deletions

View file

@ -8,7 +8,6 @@ RUN apt-get update -qq && \
libjemalloc2 \
libssl-dev \
nodejs \
npm \
postgresql-client \
default-jre-headless \
poppler-utils \
@ -21,12 +20,15 @@ RUN apt-get update -qq && \
fonts-wqy-microhei \
fonts-wqy-zenhei \
libfile-mimeinfo-perl \
chromium-driver && \
npm install -g yarn && \
yarn add puppeteer@npm:puppeteer-core && \
chromium-driver \
yarnpkg && \
ln -s /usr/lib/x86_64-linux-gnu/libvips.so.42 /usr/lib/x86_64-linux-gnu/libvips.so && \
rm -rf /var/lib/apt/lists/*
ENV PATH=/usr/share/nodejs/yarn/bin:$PATH
RUN yarn add puppeteer@npm:puppeteer-core
ENV BUNDLE_PATH /usr/local/bundle/
# create app directory

View file

@ -9,14 +9,13 @@ RUN \
apt-get install -y --no-install-recommends \
libssl-dev \
nodejs \
npm \
postgresql-client && \
npm install -g yarn
yarnpkg \
postgresql-client
ENV APP_HOME /usr/src/app
ENV RAILS_ENV=production
ENV GEM_HOME=$APP_HOME/vendor/bundle/ruby/3.2.0
ENV PATH=$GEM_HOME/bin:$PATH
ENV PATH=$GEM_HOME/bin:/usr/share/nodejs/yarn/bin:$PATH
ENV BUNDLE_APP_CONFIG=.bundle
ENV BUNDLE_BUILD__SASSC=--disable-march-tune-native
@ -69,7 +68,7 @@ RUN \
libjemalloc2 \
groff-base \
postgresql-client \
npm \
nodejs \
awscli \
netcat-openbsd \
poppler-utils \
@ -77,9 +76,9 @@ RUN \
libvips42 \
graphviz \
chromium \
libfile-mimeinfo-perl && \
npm install -g yarn && \
yarn add puppeteer@npm:puppeteer-core && \
libfile-mimeinfo-perl \
yarnpkg && \
/usr/share/nodejs/yarn/bin/yarn add puppeteer@npm:puppeteer-core && \
apt-get install -y libreoffice && \
ln -s /usr/lib/x86_64-linux-gnu/libvips.so.42 /usr/lib/x86_64-linux-gnu/libvips.so

View file

@ -1 +1 @@
1.29.1.1
1.29.2

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,012 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View file

@ -1,10 +1,29 @@
<svg width="123" height="25" viewBox="0 0 123 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M42.8255 2.60401C42.8255 1.17538 44.0059 0 45.4363 0C46.8667 0 48.0588 1.17538 48.0588 2.60401C48.0588 4.03263 46.8784 5.21961 45.4363 5.21961C43.9943 5.21961 42.8255 4.04423 42.8255 2.60401Z" fill="#104DA9"/>
<path d="M48.0588 6.95947H42.8255V24.5515H48.0588V6.95947Z" fill="#104DA9"/>
<path d="M10.0168 4.32649C7.44867 4.32649 6.03182 5.4748 6.03182 7.03875C5.99499 8.78056 7.79949 9.56157 9.95676 10.0468L12.1857 10.5688C16.4983 11.516 19.6112 13.6599 19.6228 17.7003C19.6112 22.1428 16.0506 24.9729 9.99359 24.9729C3.93657 24.9729 0.133739 22.2587 0 17.0121H5.07432C5.24295 19.4402 7.20639 20.6716 9.93156 20.6716C12.6567 20.6716 14.3159 19.4634 14.3275 17.6868C14.3159 16.0513 12.8137 15.2935 10.1118 14.6536L7.41185 13.9905C3.22136 13.0084 0.641559 10.9593 0.653188 7.38093C0.629929 2.97519 4.61496 0.0367432 10.0517 0.0367432C15.4885 0.0367432 19.208 3.02159 19.2817 7.34613H14.2558C14.062 5.44001 12.523 4.32649 10.0168 4.32649Z" fill="#104DA9"/>
<path d="M21.9467 15.8928C21.9467 10.4972 25.4201 6.79712 31.041 6.79712C35.8769 6.79712 39.1215 9.46685 39.3386 13.5323H34.491C34.2139 11.7789 33.0083 10.5997 31.1262 10.5997C28.7383 10.5997 27.1703 12.502 27.1703 15.8232C27.1703 19.1444 28.7267 21.1046 31.1262 21.1046C32.8862 21.1046 34.1887 20.0511 34.491 18.172H39.3386C39.0982 22.2162 35.9971 24.9652 31.0662 24.9652C25.3619 24.9652 21.9487 21.2419 21.9487 15.8928H21.9467Z" fill="#104DA9"/>
<path d="M76.7399 15.8869C76.7399 10.3638 80.1319 6.72748 85.1713 6.72748C90.2107 6.72748 93.6027 10.3638 93.6027 15.8869C93.6027 21.41 90.2107 25 85.1713 25C80.1319 25 76.7399 21.3637 76.7399 15.8869ZM90.7438 15.8869C90.7438 12.3434 88.9993 9.16716 85.1713 9.16716C81.3433 9.16716 79.5989 12.3434 79.5989 15.8869C79.5989 19.4305 81.3433 22.5603 85.1713 22.5603C88.9993 22.5603 90.7438 19.4305 90.7438 15.8869Z" fill="#1D2939"/>
<path d="M106.622 15.8425C106.622 10.4122 109.965 6.63666 115.005 6.63666C118.881 6.63666 123 8.89269 123 15.4733V16.6235H109.492C109.626 20.4087 111.938 22.4695 115.295 22.4695C117.536 22.4695 119.22 21.5493 119.947 19.7069L122.709 20.4435C121.837 23.1132 119.075 24.9072 115.295 24.9072C109.917 24.9072 106.622 21.2709 106.622 15.8386V15.8425ZM120.044 14.3056C120.044 11.313 118.057 9.10341 114.956 9.10341C111.685 9.10341 109.638 11.5547 109.444 14.3056H120.044Z" fill="#1D2939"/>
<path d="M70.2798 0V19.6779L70.0278 19.3319L55.8709 0H52.8356V24.5515H55.9368V4.87357L70.1441 24.5515H73.381V0H70.2798Z" fill="#1D2939"/>
<path d="M104.781 9.27932V6.9595H100.71V2.70648H97.9967V6.9595H95.0893V9.27932H97.8028V20.3662C97.8028 22.858 99.4872 24.3002 101.398 24.768C101.862 24.8821 102.336 24.9382 102.805 24.9382H104.779V22.2317H103.24C101.949 22.2317 100.708 21.8644 100.708 19.5678V9.27932H104.781Z" fill="#1D2939"/>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW 2018 (64-Bit) -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="210mm" height="39.6338mm" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 20999.98 3963.38"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<style type="text/css">
<![CDATA[
.fil0 {fill:#104DA9}
.fil1 {fill:#1D2939}
]]>
</style>
</defs>
<g id="Layer_x0020_1">
<metadata id="CorelCorpID_0Corel-Layer"/>
<g id="_1970686102672">
<path class="fil0" d="M6778.09 418.79c0,-226.11 186.87,-412.17 413.17,-412.17 226.31,0 415.1,186.06 415.1,412.17 0,226.1 -186.87,413.98 -415.1,413.98 -228.23,0 -413.17,-186.05 -413.17,-413.98z"/>
<polygon class="fil0" points="7606.36,1108.16 6778.09,1108.16 6778.09,3892.51 7606.36,3892.5 "/>
<path class="fil0" d="M1585.38 691.43c-406.48,0 -630.66,181.7 -630.66,429.29 -5.78,275.69 279.74,399.29 621.23,476.05l352.75 82.63c682.57,149.96 1175.25,489.22 1177.06,1128.7 -1.82,703.16 -565.37,1151.02 -1524.03,1151.02 -958.67,0 -1560.54,-429.6 -1581.73,-1260.01l803.13 0c26.67,384.28 337.44,579.16 768.76,579.16 431.32,0 693.93,-191.23 695.76,-472.39 -1.83,-258.85 -239.59,-378.81 -667.27,-480.1l-427.38 -104.94c-663.2,-155.34 -1071.51,-479.69 -1069.58,-1046.07 -3.75,-697.28 627.02,-1162.36 1487.43,-1162.36 860.41,0 1449.21,472.39 1460.87,1156.89l-795.43 0c-30.72,-301.64 -274.27,-477.96 -670.91,-477.96l0 0.09z"/>
<path class="fil0" d="M3473.51 2521.98c0,-853.93 549.75,-1439.58 1439.37,-1439.58 765.41,0 1278.87,422.51 1313.25,1065.94l-767.25 0c-43.91,-277.51 -234.62,-464.17 -532.52,-464.17 -377.89,0 -626.1,301.03 -626.1,826.75 0,525.72 246.39,835.88 626.1,835.88 278.52,0 484.66,-166.69 532.52,-464.18l767.24 0.01c-38.03,640.09 -528.87,1075.17 -1309.29,1075.17 -902.8,0 -1443.02,-589.3 -1443.02,-1435.92l-0.3 0 0 0.1z"/>
<path class="fil1" d="M12145.71 2521.07c0,-874.11 536.88,-1449.71 1334.43,-1449.71 797.55,0 1334.42,575.5 1334.42,1449.71 0,874.21 -536.87,1442.31 -1334.42,1442.31 -797.55,0 -1334.43,-575.5 -1334.43,-1442.31zm2216.45 0c0,-560.8 -276.1,-1063.5 -882.01,-1063.5 -605.92,0 -881.91,502.7 -881.91,1063.5 0,560.8 276.09,1056.21 881.91,1056.21 605.81,0 882.01,-495.41 882.01,-1056.21z"/>
<path class="fil1" d="M16875.17 2514.07c0,-859.5 529.06,-1457.01 1326.82,-1457.01 613.43,0 1265.38,357.1 1265.38,1398.61l0 182 -2137.97 0c21.2,599.13 387.12,925.21 918.42,925.21 354.67,0 621.23,-145.6 736.31,-437.21l437.11 116.6c-138,422.51 -575.2,706.51 -1173.42,706.51 -851.19,0 -1372.65,-575.5 -1372.65,-1435.31l0 0.61 0 -0.01zm2124.27 -243.24c0,-473.6 -314.52,-823.31 -805.27,-823.31 -517.71,0 -841.65,387.93 -872.38,823.31l1677.65 0z"/>
<polygon class="fil1" points="11123.27,6.63 11123.27,3121.11 11083.42,3066.36 8842.75,6.63 8362.35,6.63 8362.35,3892.41 8853.19,3892.4 8853.19,778.02 11101.78,3892.5 11614.11,3892.5 11614.11,6.63 "/>
<path class="fil1" d="M16583.86 1475.3l0 -367.15 -644.34 0.01 0 -673.15 -429.41 0 0 673.14 -460.11 0.01 0 367.15 429.49 -0.01 0 1754.7c0,394.42 266.57,622.65 569.02,696.67 73.41,18.05 148.44,26.97 222.66,26.97l312.39 0.01 0 -428.39 -243.54 0c-204.31,0 -400.71,-58.09 -400.71,-421.59l0 -1628.36 644.65 -0.01 -0.1 0z"/>
<path class="fil0" d="M20882.01 0l-655.26 0 -773.23 0 1546.46 1546.47 0 -1430.18c-5.5,-75.87 -54,-112.82 -117.97,-116.29z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

@ -43,7 +43,7 @@ var ExperimnetTable = {
return `<a href="${data.url}">${data.count}</a>`;
},
status: function(data) {
return `<div class="my-module-status ${data.light_color ? 'status-light' : ''}"
return `<div class="my-module-status ${data.light_color ? 'status-light' : ''}"
style="background-color: ${data.color}">${data.name}</div>`;
},
assigned: function(data) {
@ -620,9 +620,11 @@ var ExperimnetTable = {
$.get(dataUrl, tableParams, (result) => {
$(this.table).find('.table-row-placeholder, .table-row-placeholder-divider').remove();
this.appendRows(result.data);
this.initDueDatePicker(result.data);
this.handleNoResults();
setTimeout(() => {
this.appendRows(result.data);
this.initDueDatePicker(result.data);
this.handleNoResults();
}, 100);
InfiniteScroll.init(this.table, {
url: dataUrl,
@ -632,9 +634,11 @@ var ExperimnetTable = {
pageSize: this.pageSize,
lastPage: !result.next_page,
customResponse: (response) => {
this.appendRows(response.data);
this.initDueDatePicker(response.data);
this.initProvisioningStatusPolling();
setTimeout(() => {
this.appendRows(response.data);
this.initDueDatePicker(response.data);
this.initProvisioningStatusPolling();
}, 100);
},
customParams: (params) => {
return { ...params, ...tableParams };

View file

@ -12,7 +12,12 @@ var selectedRow = null;
function initEditMyModuleDescription() {
var viewObject = $('#my_module_description_view');
viewObject.on('click', function(e) {
if ($(e.target).hasClass('record-info-link') || $(e.target).parent().hasClass('record-info-link')) return;
if (e && $(e.target).prop("tagName") === 'A') return;
if (e && $(e.target).hasClass('atwho-user-popover')) return;
if (e && $(e.target).hasClass('record-info-link')) return;
if (e && $(e.target).parent().hasClass('record-info-link')) return;
if (e && $(e.target).parent().hasClass('atwho-inserted')) return;
TinyMCE.init(
'#my_module_description_textarea',
{

View file

@ -201,6 +201,8 @@ var MarvinJsEditorApi = (function() {
$('#modal_link' + json.id + ' .attachment-label').text(json.file_name);
}
$(marvinJsModal).modal('hide');
config.editor.focus();
config.button.dataset.inProgress = false;
if (MarvinJsEditor.saveCallback) MarvinJsEditor.saveCallback();
@ -261,6 +263,7 @@ var MarvinJsEditorApi = (function() {
} else if (config.mode === 'edit') {
config.objectType = 'Asset';
MarvinJsEditor.update(config);
location.reload();
} else if (config.mode === 'new-tinymce') {
config.objectType = 'TinyMceAsset';
MarvinJsEditor.save(config);
@ -319,6 +322,7 @@ $(document).on('click', '.gene-sequence-edit-button', function() {
function initMarvinJs() {
if (typeof (ChemicalizeMarvinJs) === 'undefined') {
setTimeout(initMarvinJs, 100);
return;
}
MarvinJsEditor = MarvinJsEditorApi();

View file

@ -128,31 +128,33 @@ var zebraPrint = (function() {
+ printingStatus));
}
function print(device, progressModal, numberOfCopies, printerName, labels) {
var counter = 0;
function print(device, progressModal, numberOfCopies, printerName, labels, labelIndex) {
if (labels.length <= labelIndex) {
updateProgressModalData(progressModal, printerName, PRINTER_STATUS_READY, PRINTER_STATUS_DONE);
return;
}
const label = labels[labelIndex];
function printNextLabel() {
print(device, progressModal, numberOfCopies, printerName, labels, labelIndex + 1);
}
function unsuccessfulPrint() {
updateProgressModalData(progressModal, printerName, PRINTER_STATUS_ERROR, PRINTER_STATUS_ERROR);
}
try {
updateProgressModalData(progressModal, printerName, PRINTER_STATUS_READY, PRINTER_STATUS_PRINTING);
labels.forEach(function(label) {
for (counter = 0; counter < numberOfCopies; counter += 1) {
if (counter + 1 === parseInt(numberOfCopies, 10)) {
device.sendThenRead(
label,
() => {
updateProgressModalData(progressModal, printerName, PRINTER_STATUS_READY, PRINTER_STATUS_DONE);
},
(error)=> {
updateProgressModalData(progressModal, printerName, PRINTER_STATUS_ERROR, PRINTER_STATUS_ERROR);
}
);
} else {
device.send(label, ()=>{}, (error)=> {
updateProgressModalData(progressModal, printerName, PRINTER_STATUS_ERROR, PRINTER_STATUS_ERROR);
});
}
for (let counter = 0; counter < numberOfCopies; counter += 1) {
if (counter + 1 === parseInt(numberOfCopies, 10)) {
device.sendThenRead(label, printNextLabel, unsuccessfulPrint);
} else {
device.send(label, () => {}, unsuccessfulPrint);
}
});
}
} catch (error) {
updateProgressModalData(progressModal, printerName, PRINTER_STATUS_ERROR, PRINTER_STATUS_ERROR);
unsuccessfulPrint();
}
}
@ -204,8 +206,12 @@ var zebraPrint = (function() {
getPrinterStatus(device).then((device) => {
if (device.status === I18n.t('label_printers.modal_printing_status.printer_status.ready')) {
print(
device, progressModal, printData.number_of_copies,
printData.printer_name, dataZebra.responseJSON.labels
device,
progressModal,
printData.number_of_copies,
printData.printer_name,
dataZebra.responseJSON.labels,
0,
);
} else {
updateProgressModalData(progressModal, printData.printer_name, PRINTER_STATUS_ERROR, PRINTER_STATUS_ERROR);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -226,7 +226,6 @@
.file-preview-link {
display: inline-block;
min-width: 140px;
padding-left: 5px;
}
}

View file

@ -73,6 +73,7 @@ module Api
def load_team
@team = current_user.teams.find(params.require(:team_id))
current_user.permission_team = @team
raise PermissionError.new(Team, :read) unless can_read_team?(@team)
end

View file

@ -36,19 +36,8 @@ class AssetsController < ApplicationController
def toggle_view_mode
@asset.view_mode = toggle_view_mode_params[:view_mode]
@asset.save!(touch: false)
gallery_view_id = if @assoc.is_a?(Step)
@assoc.id
elsif @assoc.is_a?(Result)
@assoc.my_module.id
end
render json: {
html: render_to_string(
partial: 'assets/asset', locals: {
asset: @asset,
gallery_view_id: gallery_view_id
}
)
}
render json: AssetSerializer.new(@asset, scope: { user: current_user }).as_json
end
def load_asset

View file

@ -53,7 +53,7 @@ class ReportsController < ApplicationController
report = current_team.reports.new(project: @project)
end
if lookup_context.template_exists?("reports/templates/#{template}/edit")
if Rails.root.join('app', 'views', 'reports', 'templates', template, 'edit.html.erb').exist?
render json: {
html: render_to_string(
template: "reports/templates/#{template}/edit",

View file

@ -47,27 +47,35 @@ class RepositoryRowsController < ApplicationController
@repository_row = @repository.repository_rows.find_by(id: params[:id])
return render_404 unless @repository_row
@my_module = if params[:my_module_id].present?
MyModule.repository_row_assignable_by_user(current_user).find_by(id: params[:my_module_id])
end
return render_403 if @my_module && !can_read_my_module?(@my_module)
respond_to do |format|
format.html do
redirect_to repository_path(@repository)
end
if @my_module
@my_module_assign_error = if !can_assign_my_module_repository_rows?(@my_module)
I18n.t('repository_row.modal_info.assign_to_task_error.no_access')
elsif @repository_row.my_modules.where(id: @my_module.id).any?
I18n.t('repository_row.modal_info.assign_to_task_error.already_assigned')
end
format.json do
@my_module = if params[:my_module_id].present?
MyModule.repository_row_assignable_by_user(current_user).find_by(id: params[:my_module_id])
end
return render_403 if @my_module && !can_read_my_module?(@my_module)
if @my_module
@my_module_assign_error = if !can_assign_my_module_repository_rows?(@my_module)
I18n.t('repository_row.modal_info.assign_to_task_error.no_access')
elsif @repository_row.my_modules.where(id: @my_module.id).any?
I18n.t('repository_row.modal_info.assign_to_task_error.already_assigned')
end
end
@assigned_modules = @repository_row.my_modules
.joins(experiment: :project)
.joins(:my_module_repository_rows)
.select('my_module_repository_rows.created_at, my_modules.*')
.order('my_module_repository_rows.created_at': :desc)
.distinct
@viewable_modules = @assigned_modules.viewable_by_user(current_user, current_user.teams)
@reminders_present = @repository_row.repository_cells.with_active_reminder(@current_user).any?
end
end
@assigned_modules = @repository_row.my_modules
.joins(experiment: :project)
.joins(:my_module_repository_rows)
.select('my_module_repository_rows.created_at, my_modules.*')
.order('my_module_repository_rows.created_at': :desc)
.distinct
@viewable_modules = @assigned_modules.viewable_by_user(current_user, current_user.teams)
@reminders_present = @repository_row.repository_cells.with_active_reminder(@current_user).any?
end
def create

View file

@ -164,7 +164,7 @@ class ResultsController < ApplicationController
def apply_filters!
if params[:query].present?
@results = @results.search(current_user, params[:archived] == 'true', params[:query], params[:page] || 1)
@results = @results.search(current_user, params[:view_mode] == 'archived', params[:query], params[:page] || 1)
end
@results = @results.where('created_at >= ?', params[:created_at_from]) if params[:created_at_from]

View file

@ -1,6 +1,8 @@
# frozen_string_literal: true
class UserNotificationsController < ApplicationController
prepend_before_action -> { request.env['devise.skip_trackable'] = true }, only: :unseen_counter
def index
page = (params[:page] || 1).to_i
notifications = load_notifications.page(page).per(Constants::INFINITE_SCROLL_LIMIT).without_count

View file

@ -64,12 +64,10 @@ module ReportsHelper
"<span class=\"label step-label-#{style}\">[#{text}]</span>".html_safe
end
def font_awesome_cdn_link_tag
stylesheet_link_tag(
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/fontawesome.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/regular.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/solid.min.css'
)
def font_awesome_links
[{ url: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/fontawesome.min.css' },
{ url: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/regular.min.css' },
{ url: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/solid.min.css' }]
end
def filter_steps_for_report(steps, settings)

View file

@ -178,10 +178,12 @@ window.TinyMCE = (() => {
if (typeof tinyMCE !== 'undefined') {
// Hide element containing HTML view of RTE field
const tinyMceContainer = $(selector).closest('form').find('.tinymce-view');
const editorForm = $(selector).closest('form');
const tinyMceInitSize = tinyMceContainer.height();
$(selector).closest('.form-group, .tinymce-editor-container')
.before(`<div class="tinymce-placeholder" style="height:${tinyMceInitSize}px"></div>`);
editorForm.parent().height(tinyMceInitSize);
tinyMceContainer.addClass('hidden');
const plugins = `
image table autosave autoresize link advlist codesample code autolink lists
charmap anchor searchreplace wordcount visualblocks visualchars
@ -205,6 +207,12 @@ window.TinyMCE = (() => {
cache_suffix: '?v=6.5.1-19', // This suffix should be changed any time library is updated
selector,
skin: false,
editimage_fetch_image: img => new Promise((resolve) => {
// Appending a timestamp to an image URL bypasses Chromes cache, resolving occasional CORS errors
fetch(img.src + '?t=' + new Date().getTime())
.then(response => response.blob())
.then(blob => resolve(blob));
}),
content_css: false,
content_style: contentStyle,
convert_urls: false,
@ -301,11 +309,14 @@ window.TinyMCE = (() => {
const editorForm = editorContainer.closest('form');
const menuBar = editorForm.find('.tox-menubar');
$('.tinymce-placeholder').css('height', `${$(editor.editorContainer).height()}px`);
setTimeout(() => {
editorContainer.addClass('tox-tinymce--loaded');
$('.tinymce-placeholder').remove();
}, 400);
editorContainer.addClass('tox-tinymce--loaded');
const event = new CustomEvent('tinyMCEOpened', {
detail: {
target: editorForm.parent(),
}
});
window.dispatchEvent(event);
editorForm.parent().css('height', '');
// Init saved status label
if (editor.getContent() !== '') {

View file

@ -6,8 +6,6 @@
export default {
bind(el, binding, vnode) {
el._vueClickOutside_ = (e) => {
e.stopPropagation();
let clickedOnExcludedEl = false;
const { exclude } = binding.value;
exclude.forEach(refName => {

View file

@ -22,20 +22,114 @@ export default {
mounted() {
this.secondaryNavigation = document.querySelector('#taskSecondaryMenu');
this.resizeObserver = new ResizeObserver((entries) => {
entries.forEach((entry) => {
this.taskSecondaryMenuHeight = entry.target.offsetHeight;
if (this.secondaryNavigation) {
this.resizeObserver = new ResizeObserver((entries) => {
entries.forEach((entry) => {
this.taskSecondaryMenuHeight = entry.target.offsetHeight;
});
});
});
this.resizeObserver.observe(this.secondaryNavigation);
this.resizeObserver.observe(this.secondaryNavigation);
}
window.addEventListener('tinyMCEOpened', (e) => {
this.handleTinyMCEOpened(e.detail.target);
});
},
beforeDestroy() {
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
window.removeEventListener('tinyMCEOpened', this.handleTinyMCEOpened);
},
methods: {
handleTinyMCEOpened(target) {
const getVisibleHeight = (elemTop, elemHeight) => {
let visibleHeight = 0;
if (elemTop >= 0) {
visibleHeight = Math.min(elemHeight, window.innerHeight - elemTop);
} else if (elemTop + elemHeight > 0) {
visibleHeight = elemTop + elemHeight;
}
return visibleHeight;
};
let headerHeight = 0;
let headerTop = 0;
let secondaryNavigationHeight = 0;
let secondaryNavigationTop = 0;
if (this.headerRef) {
headerHeight = this.headerRef.offsetHeight;
headerTop = this.headerRef.getBoundingClientRect().top;
}
if (this.secondaryNavigation) {
secondaryNavigationHeight = this.secondaryNavigation.offsetHeight;
secondaryNavigationTop = this.secondaryNavigation.getBoundingClientRect().top;
}
const editorHeaderTop = target.offset().top;
let totalHeight = 0;
const visibleHeaderHeight = getVisibleHeight(headerTop, headerHeight);
if (headerTop + visibleHeaderHeight < editorHeaderTop) {
totalHeight += visibleHeaderHeight;
}
const visibleSecondaryNavHeight = getVisibleHeight(secondaryNavigationTop, secondaryNavigationHeight);
if (secondaryNavigationTop + visibleSecondaryNavHeight < editorHeaderTop) {
totalHeight += visibleSecondaryNavHeight;
}
const editorHeader = $('.tox-editor-header');
// For Protocol Templates
if (!this.headerRef && !this.secondaryNavigation) {
if (target[0].getBoundingClientRect().top < 0 && editorHeader.css('position') !== 'fixed') {
$('html, body').animate({
scrollTop: target.offset().top - editorHeader.outerHeight(),
}, 100); // 100ms works best for editorHeader to be fully visible
} else {
editorHeader.css('left', '');
}
return;
}
// Handle opening TinyMCE toolbars when only a small bottom area of editor is visible
const targetBottom = target[0].getBoundingClientRect().bottom;
if (targetBottom < 3 * headerHeight) {
this.$nextTick(() => {
if (editorHeader.css('position') === 'fixed') {
editorHeader.css({
top: totalHeight - 1,
left: '',
});
}
$('html, body').animate({
scrollTop: target.offset().top + (visibleHeaderHeight + visibleSecondaryNavHeight),
}, 100);
});
return;
}
const headerBottom = this.headerRef.getBoundingClientRect().bottom;
// Handle showing TinyMCE toolbar for fixed/static position of toolbar
if (editorHeader.css('position') === 'fixed') {
editorHeader.css('left', '');
if (this.headerSticked) {
editorHeader.css('top', totalHeight - 1);
}
} else if (headerTop < (visibleHeaderHeight + visibleSecondaryNavHeight)
&& target[0].getBoundingClientRect().top <= headerBottom) {
this.$nextTick(() => {
$('html, body').animate({
scrollTop: target.offset().top + (visibleHeaderHeight + visibleSecondaryNavHeight),
}, 100);
});
}
target.focus();
},
initStackableHeaders() {
const header = this.headerRef;
const headerHeight = header.offsetHeight;
@ -93,7 +187,7 @@ export default {
// Apply TinyMCE offset
$('.tox-editor-header').css(
'top',
stickyNavigationHeight + parseInt($(this.secondaryNavigation).css('top'), 10)
stickyNavigationHeight + parseInt($(this.secondaryNavigation).css('top'), 10) - 1,
);
this.lastScrollTop = window.scrollY; // Save last scroll position to when user scroll up/down
},

View file

@ -5,6 +5,7 @@
:min-width="208"
width="auto"
height="100%"
class="!h-full"
:active="['r']"
@resize:start="onResizeStart"
@resize:move="onResizeMove"

View file

@ -6,16 +6,18 @@
</div>
<hr>
<perfect-scrollbar ref="scrollContainer" class="sci--navigation--notificaitons-flyout-notifications">
<div class="sci-navigation--notificaitons-flyout-subtitle" v-if="todayNotifications.length" >
<div class="sci-navigation--notificaitons-flyout-subtitle" v-if="todayNotifications.length">
{{ i18n.t('nav.notifications.today') }}
</div>
<NotificationItem v-for="notification in todayNotifications" :key="notification.type_of + '-' + notification.id" :notification="notification" />
<div class="sci-navigation--notificaitons-flyout-subtitle" v-if="olderNotifications.length" >
<NotificationItem v-for="notification in todayNotifications" :key="notification.type_of + '-' + notification.id"
:notification="notification" />
<div class="sci-navigation--notificaitons-flyout-subtitle" v-if="olderNotifications.length">
{{ i18n.t('nav.notifications.older') }}
</div>
<NotificationItem v-for="notification in olderNotifications" :key="notification.type_of + '-' + notification.id" :notification="notification" />
<NotificationItem v-for="notification in olderNotifications" :key="notification.type_of + '-' + notification.id"
:notification="notification" />
<div class="next-page-loader">
<img src="/images/medium/loading.svg" v-if="loadingPage"/>
<img src="/images/medium/loading.svg" v-if="loadingPage" />
</div>
</perfect-scrollbar>
</div>
@ -47,12 +49,17 @@ export default {
},
mounted() {
let container = this.$refs.scrollContainer.$el
document.body.style.overflow = 'hidden'
container.addEventListener('ps-scroll-y', (e) => {
if (e.target.scrollTop + e.target.clientHeight >= e.target.scrollHeight - 20) {
this.loadNotifications();
}
})
},
destroyed() {
document.body.style.overflow = 'scroll'
},
computed: {
filteredNotifications() {
this.loadNotifications();

View file

@ -139,12 +139,6 @@
type: 'PATCH',
dataType: 'json',
data: { asset: { view_mode: viewMode } }
}).done(data => {
this.$nextTick(function() {
$(`.asset[data-asset-id=${this.attachment.id}] img`)
.replaceWith($(data.html).find(`.asset[data-asset-id=${this.attachment.id}] img`));
ActiveStoragePreviews.reloadPreview(`.asset[data-asset-id=${this.attachment.id}] img`);
})
});
},
deleteAttachment() {

View file

@ -10,7 +10,7 @@ export default {
$wopiModal.find('#element_id').val(object.id);
$wopiModal.find('#element_type').val(object.attributes.type);
$wopiModal.modal('show');
$($wopiModal).find('#new-wopi-file-name').focus();
$($wopiModal).find('#new-wopi-file-name').focus().val('');
// Clear filename input error on input change if appropriate
$wopiModal.on('input', '#new-wopi-file-name', (e) => {
@ -19,16 +19,17 @@ export default {
}
});
$wopiModal.find('form')
.on('submit', () => {
animateSpinner(null, true);
})
$wopiModal.find('form').on('submit', () => {
animateSpinner(null, true);
})
.on(
'ajax:success',
(e, data, status) => {
animateSpinner(null, false);
if (status === 'success') {
$wopiModal.modal('hide');
$wopiModal.find('form').off('submit');
$wopiModal.find('form').off('ajax:success');
window.open(data.edit_url, '_blank');
window.focus();
} else {
@ -36,7 +37,8 @@ export default {
}
requestCallback(e, data, status);
}
).on('ajax:error', function(ev, response) {
)
.on('ajax:error', function(ev, response) {
let element;
let msg;

View file

@ -86,6 +86,7 @@
return {
editingName: false,
editingTable: false,
editingCell: false,
tableObject: null,
nameModalOpen: false,
reloadHeader: 0,
@ -125,6 +126,12 @@
return menu;
}
},
created() {
window.addEventListener('beforeunload', this.showSaveWarning);
},
beforeDestroy() {
window.removeEventListener('beforeunload', this.showSaveWarning);
},
updated() {
if(!this.updatingTableData) this.loadTableData();
},
@ -140,6 +147,12 @@
}
},
methods: {
showSaveWarning(e) {
if (this.editingCell) {
e.preventDefault();
e.returnValue = '';
}
},
enableTableEdit() {
if(this.locked) {
return;
@ -256,7 +269,24 @@
readOnly: !this.editingTable,
afterUnlisten: () => {
this.updatingTableData = true;
setTimeout(this.updateTable, 100) // delay makes cancel button work
this.updateTable();
},
afterChange: () => {
if (this.editingTable == false) return;
this.updatingTableData = true;
this.$nextTick(() => {
this.update(() => this.editingCell = false);
});
},
beforeKeyDown: (e) => {
if (e.keyCode === 27) { // esc
this.editingCell = false;
return;
}
},
afterBeginEditing: (e) => {
this.editingCell = true;
}
});
this.$nextTick(this.tableObject.render);

View file

@ -7,6 +7,7 @@
:placeholder="placeholder"
:id="id"
type="text"
autocomplete="off"
class="sci-input-field"
@focus="showHistory"
@blur="hideHistory"

View file

@ -15,97 +15,170 @@ module Reports
PREVIEW_EXTENSIONS = %w(docx pdf).freeze
def perform(report_id, user_id:)
report = Report.find(report_id)
user = User.find(user_id)
file = Tempfile.new(['report', '.pdf'], binmode: true)
begin
template =
if Extends::REPORT_TEMPLATES.key?(report.settings[:template]&.to_sym)
report.settings[:template]
else
Extends::REPORT_TEMPLATES.keys.first.to_s
end
raise StandardError, 'Report template not found!' if template.blank?
I18n.backend.date_format = user.settings[:date_format]
ActionController::Renderer::RACK_KEY_TRANSLATION['warden'] ||= 'warden'
proxy = Warden::Proxy.new({}, Warden::Manager.new({}))
proxy.set_user(user, scope: :user, store: false)
ApplicationController.renderer.defaults[:http_host] = Rails.application.routes.default_url_options[:host]
renderer = ApplicationController.renderer.new(warden: proxy)
Rails.application.config.x.custom_sanitizer_config = build_custom_sanitizer_config
header_html = renderer.render_to_string(
template: "reports/templates/#{template}/header",
layout: false,
locals: { report: report, user: user, logo: report_logo }
)
footer_html = renderer.render_to_string(
template: "reports/templates/#{template}/footer",
layout: false,
locals: { report: report, user: user, logo: report_logo }
)
report_html = renderer.render_to_string(
template: 'reports/report',
layout: false,
assigns: { settings: report.settings },
locals: { report: report, user: user }
)
Grover.new(
report_html,
format: 'A4',
print_background: true,
margin: { top: '2cm', bottom: '5cm', left: '1cm', right: '2cm' },
display_header_footer: true,
header_template: header_html,
footer_template: footer_html
).to_pdf(file.path)
file.rewind
file = prepend_title_page(file, template, report, renderer)
file = append_result_asset_previews(report, file, user) if report.settings.dig(:task, :file_results_previews)
report.pdf_file.attach(io: file, filename: 'report.pdf')
report.pdf_ready!
report_path = Rails.application.routes.url_helpers
.reports_path(team: report.team.id, preview_report_id: report.id, preview_type: :pdf)
notification = Notification.create(
type_of: :deliver,
title: I18n.t('projects.reports.index.generation.completed_pdf_notification_title'),
message: I18n.t('projects.reports.index.generation.completed_notification_message',
report_link: "<a href='#{report_path}'>#{escape_input(report.name)}</a>",
team_name: escape_input(report.team.name))
)
notification.create_user_notification(user)
ensure
Rails.application.config.x.custom_sanitizer_config = nil
I18n.backend.date_format = nil
file.close(true)
end
@report = Report.find(report_id)
@user = User.find(user_id)
@file = Tempfile.new(['report', '.pdf'], binmode: true)
initialize_template
set_renderer_context
generate_pdf_content
process_attach_pdf_report_and_notify
rescue StandardError => e
raise e if report.blank?
raise e if @report.blank?
ActiveRecord::Base.no_touching do
report.pdf_error!
@report.pdf_error!
end
Rails.logger.error("Couldn't generate PDF for Report with id: #{report.id}. Error:\n #{e.message}")
Rails.logger.error("Couldn't generate PDF for Report with id: #{@report.id}. Error:\n #{e.message}")
raise e
ensure
Rails.application.config.x.custom_sanitizer_config = nil
I18n.backend.date_format = nil
@file.close(true)
end
private
def append_result_asset_previews(report, report_file, user)
def initialize_template
@template = if Extends::REPORT_TEMPLATES.key?(@report.settings[:template]&.to_sym)
@report.settings[:template]
else
Extends::REPORT_TEMPLATES.keys.first.to_s
end
raise StandardError, 'Report template not found!' if @template.blank?
end
def set_renderer_context
I18n.backend.date_format = @user.settings[:date_format]
ActionController::Renderer::RACK_KEY_TRANSLATION['warden'] ||= 'warden'
proxy = Warden::Proxy.new({}, Warden::Manager.new({}))
proxy.set_user(@user, scope: :user, store: false)
ApplicationController.renderer.defaults[:http_host] = Rails.application.routes.default_url_options[:host]
@renderer = ApplicationController.renderer.new(warden: proxy)
Rails.application.config.x.custom_sanitizer_config = build_custom_sanitizer_config
end
def generate_pdf_content
@has_cover = Rails.root.join('app', 'views', 'reports', 'templates', @template, 'cover.html.erb').exist?
render_header_footer_and_report
gather_styles_and_scripts
generate_pdf_file
end
def render_header_footer_and_report
@header_html = @renderer.render_to_string(
template: "reports/templates/#{@template}/header",
layout: false,
locals: { report: @report, user: @user, logo: report_logo }
)
@footer_html = @renderer.render_to_string(
template: "reports/templates/#{@template}/footer",
layout: false,
locals: { report: @report, user: @user, logo: report_logo }
)
@report_html = @renderer.render_to_string(
template: 'reports/report',
layout: false,
assigns: { settings: @report.settings },
locals: { report: @report, user: @user, has_cover: @has_cover }
)
end
def gather_styles_and_scripts
css_files = [
'application',
'reports_pdf',
'bootstrap_pack',
'handsontable.formula'
]
javascript_files = [
'jquery_bundle',
'handsontable.full',
'lodash',
'numeral',
'numeric',
'md5',
'jstat',
'formula',
'parser',
'ruleJS',
'big.min',
'handsontable.formula',
'reports/content',
'reports/template_helpers'
]
@style_tag_options = []
@script_tag_options = []
@style_tag_options = css_files.map do |file_name|
{ content: fetch_asset_content("#{file_name}.css") }
end
@style_tag_options.concat(font_awesome_links)
@script_tag_options = javascript_files.map do |file_name|
{ content: fetch_asset_content("#{file_name}.js") }
end
end
def generate_pdf_file
current_margin = extract_margins_from_header ||
{ top: '2cm', bottom: '2cm', left: '1cm', right: '1.5cm' }
cover_pages_shift = cover_page_shift_from_template
Grover.new(
@report_html,
format: 'A4',
print_background: true,
margin: current_margin,
display_header_footer: true,
header_template: @header_html,
footer_template: @footer_html,
style_tag_options: @style_tag_options,
script_tag_options: @script_tag_options,
page_ranges: "#{cover_pages_shift}-999999",
emulate_media: 'screen',
display_url: Rails.application.routes.default_url_options[:host]
).to_pdf(@file.path)
end
def process_attach_pdf_report_and_notify
@file.rewind
@file = prepend_title_page if @has_cover
@file = append_result_asset_previews if @report.settings.dig(:task, :file_results_previews)
@report.pdf_file.attach(io: @file, filename: 'report.pdf')
@report.pdf_ready!
create_notification_for_user
end
def create_notification_for_user
report_path = Rails.application.routes.url_helpers
.reports_path(team: @report.team.id, preview_report_id: @report.id, preview_type: :pdf)
notification = Notification.create(
type_of: :deliver,
title: I18n.t('projects.reports.index.generation.completed_pdf_notification_title'),
message: I18n.t('projects.reports.index.generation.completed_notification_message',
report_link: "<a href='#{report_path}'>#{escape_input(@report.name)}</a>",
team_name: escape_input(@report.team.name))
)
notification.create_user_notification(@user)
end
def append_result_asset_previews
Dir.mktmpdir do |tmp_dir|
report.report_elements.my_module.each do |my_module_element|
next unless can_read_my_module?(user, my_module_element.my_module)
@report.report_elements.my_module.each do |my_module_element|
next unless can_read_my_module?(@user, my_module_element.my_module)
results = my_module_element.my_module.results
order_results_for_report(results, report.settings.dig(:task, :result_order)).each do |result|
order_results_for_report(results, @report.settings.dig(:task, :result_order)).each do |result|
result.assets.each do |asset|
next unless PREVIEW_EXTENSIONS.include?(asset.file.blob.filename.extension)
@ -114,13 +187,13 @@ module Reports
asset.reload
end
asset.file_pdf_preview.open(tmpdir: tmp_dir) do |file|
report_file = merge_pdf_files(file, report_file)
@file = merge_pdf_files(file, @file)
end
end
end
end
end
report_file
@file
end
def merge_pdf_files(file, report_file)
@ -149,14 +222,10 @@ module Reports
merged_file
end
def prepend_title_page(file, template, report, renderer)
unless File.exist?(Rails.root.join('app', 'views', 'reports', 'templates', template, 'cover'))
return file
end
def prepend_title_page
total_pages = 0
IO.popen(['pdfinfo', file.path], 'r+') do |f|
IO.popen(['pdfinfo', @file.path], 'r+') do |f|
total_pages = f.read.split("\n")
.find { |i| i.split(':')[0] == 'Pages' }
.gsub(/[^0-9]/, '')
@ -165,27 +234,32 @@ module Reports
title_page = Tempfile.new(['title_page', '.pdf'], binmode: true)
merged_file = Tempfile.new(['report', '.pdf'], binmode: true)
title_page_html = renderer.render_to_string(
template: "reports/templates/#{template}/cover",
title_page_html = @renderer.render_to_string(
template: "reports/templates/#{@template}/cover",
layout: false,
formats: :html,
locals: { report: report, total_pages: total_pages.to_i, logo: report_logo }
locals: { report: @report, total_pages: total_pages.to_i, logo: report_logo }
)
Grover.new(
title_page_html,
format: 'A4'
format: 'A4',
style_tag_options: @style_tag_options,
script_tag_options: @script_tag_options,
emulate_media: 'screen',
print_background: true,
display_url: Rails.application.routes.default_url_options[:host]
).to_pdf(title_page.path)
title_page.rewind
success = system(
'pdfunite', title_page.path, file.path, merged_file.path
'pdfunite', title_page.path, @file.path, merged_file.path
)
raise StandardError, 'There was an error merging report and title page' unless success && File.file?(merged_file)
file.close(true)
@file.close(true)
title_page.close(true)
merged_file
@ -226,5 +300,44 @@ module Reports
report_link: "<a href='#{report_path}'>#{escape_input(report.name)}</a>",
team_name: escape_input(report.team.name))
end
def fetch_asset_content(asset_name)
Rails.application
.assets_manifest
.find_sources(asset_name)
.first
.to_s
.force_encoding(Encoding::UTF_8)
end
def extract_margins_from_header
header_file_path = Rails.root.join('app', 'views', 'reports', 'templates', @template, 'header.html.erb')
return nil unless header_file_path.exist?
content = File.read(header_file_path)
margin_comment = content.match(/<!--\s*margins:(.*)\s*-->/)
return nil unless margin_comment
margins = {}
margin_comment[1].split(',').each do |margin_pair|
key, value = margin_pair.split(':').map(&:strip)
margins[key.to_sym] = value
end
margins
end
def cover_page_shift_from_template
cover_file_path = Rails.root.join('app', 'views', 'reports', 'templates', @template, 'cover.html.erb')
return 1 unless cover_file_path.exist?
content = File.read(cover_file_path)
cover_pages_comment = content.match(/<!--\s*cover_pages_count:(\d+)\s*-->/)
return 2 unless cover_pages_comment
cover_pages_comment[1].to_i + 1
end
end
end

View file

@ -187,11 +187,19 @@ class TeamZipExportJob < ZipExportJob
def prepare_preview(asset)
if asset.previewable? && !asset.list?
preview = asset.inline? ? asset.large_preview : asset.medium_preview
return unless preview.image.attached?
begin
file_name = preview.image.filename.to_s
file_data = preview.image.download
if preview.is_a?(ActiveStorage::Preview)
return unless preview.image.attached?
file_name = preview.image.filename.to_s
file_data = preview.image.download
else
return unless preview.processed?
file_name = preview.blob.filename.to_s
file_data = preview.download
end
rescue ActiveStorage::FileNotFoundError => e
Rails.logger.error(e.message)
Rails.logger.error(e.backtrace.join("\n"))

View file

@ -28,6 +28,7 @@ module UserAssignments
.where(user_assignments: { user: users })
.where(projects: project)
# rubocop:disable Rails/SkipsModelValidations
UserMyModule.where(user: users, my_module: my_modules).delete_all # remove designated users
UserAssignment.where(assignable_type: 'MyModule', assignable_id: my_modules, user: users).delete_all
my_modules.update_all(updated_at: Time.current)
# rubocop:enable Rails/SkipsModelValidations

View file

@ -473,7 +473,7 @@ class Asset < ApplicationRecord
def previewable_image?
preview_image.attached? ||
file.blob&.content_type =~ %r{^image/#{Regexp.union(Constants::WHITELISTED_IMAGE_TYPES)}}
file.blob&.content_type&.match?(%r{^image/#{Regexp.union(Constants::WHITELISTED_IMAGE_TYPES)}})
end
def step_or_result_or_repository_asset_value

View file

@ -43,9 +43,16 @@ class Result < ApplicationRecord
new_query =
Result
.distinct
.left_outer_joins(:result_texts)
.left_outer_joins(:result_texts, result_tables: :table)
.where(results: { my_module_id: module_ids })
.where_attributes_like(['results.name', 'result_texts.text'], query, options)
.where_attributes_like(
[
'results.name',
'result_texts.name',
'result_texts.text',
'tables.name'
], query, options
)
new_query = new_query.active unless include_archived

View file

@ -0,0 +1,11 @@
# frozen_string_literal: true
module Api
module V1
class RepositoryNumberValueSerializer < ActiveModel::Serializer
attribute :data
include TimestampableModel
end
end
end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
module Api
module V1
class RepositoryStockValueSerializer < ActiveModel::Serializer
attribute :repository_stock_unit_item_id, key: :inventory_stock_unit_item_id
attributes :amount, :low_stock_threshold, :comment
include TimestampableModel
end
end
end

View file

@ -33,9 +33,15 @@
<% end %>
<%= favicon_link_tag "favicon.ico" %>
<%= favicon_link_tag "favicon-16.png", type: "image/png", size: "16x16" %>
<%= favicon_link_tag "favicon-32.png", type: "image/png", size: "32x32" %>
<%= favicon_link_tag "favicon-48.png", type: "image/png", size: "48x48" %>
<%= favicon_link_tag "favicon-57x57.png", type: "image/png", size: "57x57" %>
<%= favicon_link_tag "favicon-72x72.png", type: "image/png", size: "72x72" %>
<%= favicon_link_tag "favicon-76x76.png", type: "image/png", size: "76x76" %>
<%= favicon_link_tag "favicon-114x114.png", type: "image/png", size: "114x114" %>
<%= favicon_link_tag "favicon-120x120.png", type: "image/png", size: "120x120" %>
<%= favicon_link_tag "favicon-144x144.png", type: "image/png", size: "144x144" %>
<%= favicon_link_tag "favicon-152x152.png", type: "image/png", size: "152x152" %>
<%= favicon_link_tag "favicon-180x180.png", type: "image/png", size: "180x180" %>
<%= stylesheet_link_tag 'fontawesome' %>
<%= stylesheet_link_tag 'prism' %>

View file

@ -5,6 +5,5 @@
</head>
<body>
<%= yield %>
<%= javascript_include_tag wicked_pdf_asset_base64("reports/template_helpers") %>
</body>
</html>

View file

@ -14,9 +14,14 @@
<%= stylesheet_link_tag 'datatables' %>
<%= favicon_link_tag "favicon.ico" %>
<%= favicon_link_tag "favicon-16.png", type: "image/png", size: "16x16" %>
<%= favicon_link_tag "favicon-32.png", type: "image/png", size: "32x32" %>
<%= favicon_link_tag "favicon-48.png", type: "image/png", size: "48x48" %>
<%= favicon_link_tag "favicon-57x57.png", type: "image/png", size: "57x57" %>
<%= favicon_link_tag "favicon-72x72.png", type: "image/png", size: "72x72" %>
<%= favicon_link_tag "favicon-76x76.png", type: "image/png", size: "76x76" %>
<%= favicon_link_tag "favicon-114x114.png", type: "image/png", size: "114x114" %>
<%= favicon_link_tag "favicon-120x120.png", type: "image/png", size: "120x120" %>
<%= favicon_link_tag "favicon-144x144.png", type: "image/png", size: "144x144" %>
<%= favicon_link_tag "favicon-152x152.png", type: "image/png", size: "152x152" %>
<%= favicon_link_tag "favicon-180x180.png", type: "image/png", size: "180x180" %>
<%= stylesheet_link_tag 'fontawesome' %>
<%= stylesheet_link_tag 'prism' %>

View file

@ -19,9 +19,14 @@
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= favicon_link_tag "favicon.ico" %>
<%= favicon_link_tag "favicon-16.png", type: "image/png", size: "16x16" %>
<%= favicon_link_tag "favicon-32.png", type: "image/png", size: "32x32" %>
<%= favicon_link_tag "favicon-48.png", type: "image/png", size: "48x48" %>
<%= favicon_link_tag "favicon-57x57.png", type: "image/png", size: "57x57" %>
<%= favicon_link_tag "favicon-72x72.png", type: "image/png", size: "72x72" %>
<%= favicon_link_tag "favicon-76x76.png", type: "image/png", size: "76x76" %>
<%= favicon_link_tag "favicon-114x114.png", type: "image/png", size: "114x114" %>
<%= favicon_link_tag "favicon-120x120.png", type: "image/png", size: "120x120" %>
<%= favicon_link_tag "favicon-144x144.png", type: "image/png", size: "144x144" %>
<%= favicon_link_tag "favicon-152x152.png", type: "image/png", size: "152x152" %>
<%= favicon_link_tag "favicon-180x180.png", type: "image/png", size: "180x180" %>
<%= csrf_meta_tags %>
</head>

View file

@ -1,32 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<%= wicked_pdf_stylesheet_link_tag "application" %>
<%= wicked_pdf_stylesheet_link_tag "reports_pdf" %>
<%= wicked_pdf_stylesheet_link_tag "bootstrap_pack" %>
<%= font_awesome_cdn_link_tag %>
<%= wicked_pdf_javascript_include_tag "jquery_bundle" %>
<%= wicked_pdf_javascript_include_tag "handsontable.full" %>
<!-- Libraries for formulas -->
<%= wicked_pdf_javascript_include_tag "lodash" %>
<%= wicked_pdf_javascript_include_tag "numeral" %>
<%= wicked_pdf_javascript_include_tag "numeric" %>
<%= wicked_pdf_javascript_include_tag "md5" %>
<%= wicked_pdf_javascript_include_tag "jstat" %>
<%= wicked_pdf_javascript_include_tag "formula" %>
<%= wicked_pdf_javascript_include_tag "parser" %>
<%= wicked_pdf_javascript_include_tag "ruleJS" %>
<%= wicked_pdf_javascript_include_tag "big.min" %>
<%= wicked_pdf_javascript_include_tag "handsontable.formula" %>
<%= wicked_pdf_stylesheet_link_tag "handsontable.formula" %>
<meta charset="UTF-8">
</head>
<body class="print-report-body">
<% if has_cover %>
<div style="break-after: page;"></div>
<% end %>
<div class="print-report">
<% report.root_elements.each do |el| %>
<%= render_report_element(el, local_assigns) %>
<% end %>
</div>
<%= wicked_pdf_javascript_include_tag "reports/content" %>
</body>
</html>

View file

@ -1,8 +1,10 @@
<style>
.print-footer {
line-height: 50px;
margin-right: 30px;
font-size: 13px;
padding-right: 30px;
text-align: right;
width: 100%;
}
</style>

View file

@ -1,24 +1,40 @@
<!-- margins: top:2cm,bottom:2cm,left:1cm,right:1.5cm -->
<!-- First line represents margins for pdf generation by Grover -->
<style>
.print-header {
.print-header {
display: flex;
justify-content: space-between;
align-items: center;
line-height: 40px;
font-size: 13px;
width: 100%;
position: relative;
}
.print-header::after {
content: "";
position: absolute;
left: 40px;
right: 40px;
bottom: 0;
border-bottom: 2px solid #a0a0a8;
line-height: 50px;
}
z-index: -1;
}
.logo-img {
.logo-img {
display: inline-block;
margin: 0 0 0 30px;
}
margin: 0 0 0 70px;
}
img {
width: 100px;
}
img {
width: 80px;
}
.page-numbers {
.page-numbers {
display: inline-block;
float: right;
margin: 0 30px 0 0;
padding-right: 60px;
white-space: nowrap;
}
}
</style>
<div class="print-header">
<div class="logo-img">
@ -28,8 +44,8 @@
<%= image_tag logo %>
<% end %>
</div>
<h1><span class='pageNumber'></span>/<span class='totalPages'></h1>
<div class="page-numbers pagination" data-page-offset="0">
Page <span class="page"></span> of <span class="topage"></span>
<div class="page-numbers">
Page <span class="pageNumber"></span> of <span class="totalPages"></span>
</div>
</div>

2
bin/chromium Executable file
View file

@ -0,0 +1,2 @@
#!/bin/bash
env -i /usr/bin/chromium $@

View file

@ -328,6 +328,7 @@ class Constants
config[:attributes][:all] << 'contenteditable'
config[:attributes]['img'] << 'data-mce-token'
config[:attributes]['img'] << 'data-source-type'
config[:attributes]['a'] << 'data-turbolinks'
config[:protocols]['img']['src'] << 'data'
INPUT_SANITIZE_CONFIG = Sanitize::Config.freeze_config(config)

View file

@ -3,7 +3,7 @@
Grover.configure do |config|
config.options = {
cache: false,
executable_path: '/usr/bin/chromium',
executable_path: './bin/chromium',
launch_args: ['--no-sandbox']
}
end

BIN
public/favicon-114x114.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
public/favicon-120x120.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
public/favicon-144x144.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
public/favicon-152x152.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 B

BIN
public/favicon-180x180.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,012 B

BIN
public/favicon-57x57.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
public/favicon-72x72.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
public/favicon-76x76.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -1,5 +1,29 @@
<svg width="202" height="40" viewBox="0 0 202 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M186.738 0H199.399C200.452 0 201.306 0.85327 201.306 1.90576V15.6806L186.738 0Z" fill="#104DA9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M133.795 35.4726C135.312 34.6027 136.497 33.3676 137.35 31.764C138.202 30.1612 138.629 28.3367 138.629 26.2903C138.629 24.244 138.202 22.4202 137.35 20.8166C136.497 19.2138 135.312 17.9779 133.795 17.1081C132.277 16.239 130.563 15.8038 128.653 15.8038C126.743 15.8038 125.03 16.239 123.513 17.1081C121.995 17.9779 120.801 19.2138 119.932 20.8166C119.062 22.4202 118.628 24.244 118.628 26.2903C118.628 28.3367 119.062 30.1612 119.932 31.764C120.801 33.3676 121.995 34.6027 123.513 35.4726C125.03 36.3416 126.743 36.7776 128.653 36.7776C130.563 36.7776 132.277 36.3416 133.795 35.4726ZM121.645 38.2346C119.564 37.0588 117.928 35.4305 116.735 33.3503C115.54 31.2701 114.944 28.9163 114.944 26.2903C114.944 23.6644 115.54 21.3113 116.735 19.2304C117.928 17.1509 119.564 15.5309 121.645 14.3709C123.725 13.2124 126.061 12.632 128.653 12.632C131.245 12.632 133.581 13.2124 135.662 14.3709C137.742 15.5309 139.371 17.1509 140.547 19.2304C141.724 21.3113 142.312 23.6644 142.312 26.2903C142.312 28.9163 141.724 31.2701 140.547 33.3503C139.371 35.4305 137.742 37.0588 135.662 38.2346C133.581 39.4111 131.245 39.9998 128.653 39.9998C126.061 39.9998 123.725 39.4111 121.645 38.2346ZM162.849 38.107C162.166 38.7212 161.323 39.1903 160.317 39.5144C159.311 39.8376 158.262 40 157.171 40C154.647 40 152.703 39.3189 151.339 37.9537C149.975 36.5899 149.294 34.6631 149.294 32.1732V15.9055H144.484V12.836H149.294V6.95403H152.925V12.836H161.11V15.9055H152.925V31.9687C152.925 33.5723 153.325 34.7909 154.127 35.6261C154.928 36.4629 156.079 36.8786 157.58 36.8786C158.33 36.8786 159.055 36.7606 159.754 36.5208C160.453 36.2832 161.058 35.9419 161.57 35.4983L162.849 38.107ZM172.214 18.2336C170.457 19.8882 169.46 22.0451 169.221 24.7049H188.302C188.063 22.0451 187.066 19.8882 185.31 18.2336C183.553 16.5804 181.362 15.7527 178.737 15.7527C176.144 15.7527 173.97 16.5804 172.214 18.2336ZM191.73 27.4158H169.221C169.426 30.2124 170.5 32.4715 172.444 34.1939C174.388 35.9162 176.844 36.7777 179.811 36.7777C181.481 36.7777 183.016 36.4793 184.415 35.8816C185.812 35.2862 187.024 34.4074 188.047 33.2474L190.092 35.6012C188.899 37.0333 187.407 38.1249 185.617 38.8744C183.826 39.6255 181.857 39.9999 179.709 39.9999C176.946 39.9999 174.498 39.4112 172.368 38.2347C170.236 37.0589 168.573 35.4298 167.38 33.3504C166.186 31.2702 165.59 28.9164 165.59 26.2904C165.59 23.6644 166.16 21.3114 167.304 19.2304C168.446 17.151 170.015 15.5309 172.01 14.3709C174.004 13.2124 176.247 12.6321 178.737 12.6321C181.226 12.6321 183.459 13.2124 185.438 14.3709C187.415 15.5309 188.967 17.142 190.092 19.2056C191.218 21.2693 191.781 23.6299 191.781 26.2904L191.73 27.4158ZM110.261 3.93579V39.7445H107.14L84.1208 10.6883V39.7445H80.3348V3.93579H83.4555L106.526 32.9921V3.93579H110.261Z" fill="#231F20"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.27961 38.7182C3.67319 37.9619 1.58024 36.9778 0 35.7674L2.77407 29.6141C4.2874 30.7238 6.08565 31.6154 8.17109 32.2875C10.2558 32.9603 12.3405 33.2956 14.4251 33.2956C16.7451 33.2956 18.4607 32.9513 19.5703 32.2619C20.6799 31.5733 21.2348 30.6569 21.2348 29.5134C21.2348 28.6729 20.9062 27.9753 20.2507 27.4204C19.5951 26.8656 18.7539 26.4198 17.7292 26.083C16.703 25.7477 15.316 25.3771 13.5681 24.9734C10.8775 24.3359 8.67553 23.6961 6.96073 23.0571C5.24592 22.4188 3.77468 21.3927 2.54703 19.9808C1.31937 18.5682 0.705921 16.6858 0.705921 14.3312C0.705921 12.2811 1.26073 10.4227 2.37036 8.75826C3.47999 7.09383 5.1527 5.77445 7.38924 4.79864C9.62503 3.82434 12.357 3.33568 15.5859 3.33568C17.8382 3.33568 20.0402 3.60557 22.1925 4.14309C24.3441 4.68136 26.2281 5.45419 27.8414 6.46308L25.3199 12.6675C22.058 10.8181 18.796 9.8927 15.5348 9.8927C13.2479 9.8927 11.5579 10.2633 10.4663 11.0023C9.37243 11.7428 8.82664 12.7171 8.82664 13.9275C8.82664 15.1386 9.45739 16.0385 10.7181 16.6264C11.9796 17.215 13.9034 17.7954 16.4933 18.366C19.1832 19.0058 21.3859 19.6448 23.1007 20.283C24.8155 20.9221 26.286 21.9309 27.5144 23.3097C28.7413 24.6885 29.3547 26.5551 29.3547 28.9082C29.3547 30.9252 28.7916 32.7663 27.6647 34.4308C26.5386 36.0952 24.8486 37.4153 22.5962 38.3904C20.3432 39.3647 17.6029 39.8526 14.3748 39.8526C11.5834 39.8526 8.88528 39.4745 6.27961 38.7182ZM39.7191 37.8607C37.4157 36.6676 35.6167 35.0115 34.3229 32.8929C33.0275 30.7744 32.381 28.3702 32.381 25.6796C32.381 22.9905 33.0275 20.5856 34.3229 18.467C35.6167 16.3485 37.4157 14.6931 39.7191 13.4993C42.0218 12.3062 44.62 11.7085 47.5121 11.7085C50.3696 11.7085 52.8663 12.3062 55.0021 13.4993C57.1371 14.6931 58.6918 16.3989 59.6676 18.6182L53.5647 21.8974C52.1521 19.409 50.117 18.1641 47.4617 18.1641C45.4101 18.1641 43.7118 18.8377 42.3669 20.1826C41.022 21.5275 40.3499 23.3596 40.3499 25.6796C40.3499 27.9996 41.022 29.8332 42.3669 31.1774C43.7118 32.5231 45.4101 33.1952 47.4617 33.1952C50.1508 33.1952 52.1851 31.9517 53.5647 29.4626L59.6676 32.7922C58.6918 34.9438 57.1371 36.6248 55.0021 37.8351C52.8663 39.0463 50.3696 39.6514 47.5121 39.6514C44.62 39.6514 42.0218 39.0545 39.7191 37.8607ZM64.2064 39.7731H72.0745V12.6376H64.2064V39.7731ZM64.6094 7.59316C63.702 6.75342 63.2479 5.7107 63.2479 4.46651C63.2479 3.22231 63.702 2.18034 64.6094 1.3391C65.5175 0.498614 66.6948 0.0783691 68.1405 0.0783691C69.5861 0.0783691 70.7634 0.482075 71.6708 1.28873C72.579 2.09539 73.033 3.10428 73.033 4.31465C73.033 5.6265 72.579 6.71132 71.6708 7.56835C70.7634 8.42538 69.5861 8.85464 68.1405 8.85464C66.6948 8.85464 65.5175 8.4344 64.6094 7.59316Z" fill="#104DA9"/>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW 2018 (64-Bit) -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="210mm" height="39.6338mm" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 20999.98 3963.38"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<style type="text/css">
<![CDATA[
.fil0 {fill:#104DA9}
.fil1 {fill:#1D2939}
]]>
</style>
</defs>
<g id="Layer_x0020_1">
<metadata id="CorelCorpID_0Corel-Layer"/>
<g id="_1970686102672">
<path class="fil0" d="M6778.09 418.79c0,-226.11 186.87,-412.17 413.17,-412.17 226.31,0 415.1,186.06 415.1,412.17 0,226.1 -186.87,413.98 -415.1,413.98 -228.23,0 -413.17,-186.05 -413.17,-413.98z"/>
<polygon class="fil0" points="7606.36,1108.16 6778.09,1108.16 6778.09,3892.51 7606.36,3892.5 "/>
<path class="fil0" d="M1585.38 691.43c-406.48,0 -630.66,181.7 -630.66,429.29 -5.78,275.69 279.74,399.29 621.23,476.05l352.75 82.63c682.57,149.96 1175.25,489.22 1177.06,1128.7 -1.82,703.16 -565.37,1151.02 -1524.03,1151.02 -958.67,0 -1560.54,-429.6 -1581.73,-1260.01l803.13 0c26.67,384.28 337.44,579.16 768.76,579.16 431.32,0 693.93,-191.23 695.76,-472.39 -1.83,-258.85 -239.59,-378.81 -667.27,-480.1l-427.38 -104.94c-663.2,-155.34 -1071.51,-479.69 -1069.58,-1046.07 -3.75,-697.28 627.02,-1162.36 1487.43,-1162.36 860.41,0 1449.21,472.39 1460.87,1156.89l-795.43 0c-30.72,-301.64 -274.27,-477.96 -670.91,-477.96l0 0.09z"/>
<path class="fil0" d="M3473.51 2521.98c0,-853.93 549.75,-1439.58 1439.37,-1439.58 765.41,0 1278.87,422.51 1313.25,1065.94l-767.25 0c-43.91,-277.51 -234.62,-464.17 -532.52,-464.17 -377.89,0 -626.1,301.03 -626.1,826.75 0,525.72 246.39,835.88 626.1,835.88 278.52,0 484.66,-166.69 532.52,-464.18l767.24 0.01c-38.03,640.09 -528.87,1075.17 -1309.29,1075.17 -902.8,0 -1443.02,-589.3 -1443.02,-1435.92l-0.3 0 0 0.1z"/>
<path class="fil1" d="M12145.71 2521.07c0,-874.11 536.88,-1449.71 1334.43,-1449.71 797.55,0 1334.42,575.5 1334.42,1449.71 0,874.21 -536.87,1442.31 -1334.42,1442.31 -797.55,0 -1334.43,-575.5 -1334.43,-1442.31zm2216.45 0c0,-560.8 -276.1,-1063.5 -882.01,-1063.5 -605.92,0 -881.91,502.7 -881.91,1063.5 0,560.8 276.09,1056.21 881.91,1056.21 605.81,0 882.01,-495.41 882.01,-1056.21z"/>
<path class="fil1" d="M16875.17 2514.07c0,-859.5 529.06,-1457.01 1326.82,-1457.01 613.43,0 1265.38,357.1 1265.38,1398.61l0 182 -2137.97 0c21.2,599.13 387.12,925.21 918.42,925.21 354.67,0 621.23,-145.6 736.31,-437.21l437.11 116.6c-138,422.51 -575.2,706.51 -1173.42,706.51 -851.19,0 -1372.65,-575.5 -1372.65,-1435.31l0 0.61 0 -0.01zm2124.27 -243.24c0,-473.6 -314.52,-823.31 -805.27,-823.31 -517.71,0 -841.65,387.93 -872.38,823.31l1677.65 0z"/>
<polygon class="fil1" points="11123.27,6.63 11123.27,3121.11 11083.42,3066.36 8842.75,6.63 8362.35,6.63 8362.35,3892.41 8853.19,3892.4 8853.19,778.02 11101.78,3892.5 11614.11,3892.5 11614.11,6.63 "/>
<path class="fil1" d="M16583.86 1475.3l0 -367.15 -644.34 0.01 0 -673.15 -429.41 0 0 673.14 -460.11 0.01 0 367.15 429.49 -0.01 0 1754.7c0,394.42 266.57,622.65 569.02,696.67 73.41,18.05 148.44,26.97 222.66,26.97l312.39 0.01 0 -428.39 -243.54 0c-204.31,0 -400.71,-58.09 -400.71,-421.59l0 -1628.36 644.65 -0.01 -0.1 0z"/>
<path class="fil0" d="M20882.01 0l-655.26 0 -773.23 0 1546.46 1546.47 0 -1430.18c-5.5,-75.87 -54,-112.82 -117.97,-116.29z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

@ -1,10 +1,29 @@
<svg width="123" height="25" viewBox="0 0 123 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M42.8255 2.60401C42.8255 1.17538 44.0059 0 45.4363 0C46.8667 0 48.0588 1.17538 48.0588 2.60401C48.0588 4.03263 46.8784 5.21961 45.4363 5.21961C43.9943 5.21961 42.8255 4.04423 42.8255 2.60401Z" fill="#104DA9"/>
<path d="M48.0588 6.95947H42.8255V24.5515H48.0588V6.95947Z" fill="#104DA9"/>
<path d="M10.0168 4.32649C7.44867 4.32649 6.03182 5.4748 6.03182 7.03875C5.99499 8.78056 7.79949 9.56157 9.95676 10.0468L12.1857 10.5688C16.4983 11.516 19.6112 13.6599 19.6228 17.7003C19.6112 22.1428 16.0506 24.9729 9.99359 24.9729C3.93657 24.9729 0.133739 22.2587 0 17.0121H5.07432C5.24295 19.4402 7.20639 20.6716 9.93156 20.6716C12.6567 20.6716 14.3159 19.4634 14.3275 17.6868C14.3159 16.0513 12.8137 15.2935 10.1118 14.6536L7.41185 13.9905C3.22136 13.0084 0.641559 10.9593 0.653188 7.38093C0.629929 2.97519 4.61496 0.0367432 10.0517 0.0367432C15.4885 0.0367432 19.208 3.02159 19.2817 7.34613H14.2558C14.062 5.44001 12.523 4.32649 10.0168 4.32649Z" fill="#104DA9"/>
<path d="M21.9467 15.8928C21.9467 10.4972 25.4201 6.79712 31.041 6.79712C35.8769 6.79712 39.1215 9.46685 39.3386 13.5323H34.491C34.2139 11.7789 33.0083 10.5997 31.1262 10.5997C28.7383 10.5997 27.1703 12.502 27.1703 15.8232C27.1703 19.1444 28.7267 21.1046 31.1262 21.1046C32.8862 21.1046 34.1887 20.0511 34.491 18.172H39.3386C39.0982 22.2162 35.9971 24.9652 31.0662 24.9652C25.3619 24.9652 21.9487 21.2419 21.9487 15.8928H21.9467Z" fill="#104DA9"/>
<path d="M76.7399 15.8869C76.7399 10.3638 80.1319 6.72748 85.1713 6.72748C90.2107 6.72748 93.6027 10.3638 93.6027 15.8869C93.6027 21.41 90.2107 25 85.1713 25C80.1319 25 76.7399 21.3637 76.7399 15.8869ZM90.7438 15.8869C90.7438 12.3434 88.9993 9.16716 85.1713 9.16716C81.3433 9.16716 79.5989 12.3434 79.5989 15.8869C79.5989 19.4305 81.3433 22.5603 85.1713 22.5603C88.9993 22.5603 90.7438 19.4305 90.7438 15.8869Z" fill="#1D2939"/>
<path d="M106.622 15.8425C106.622 10.4122 109.965 6.63666 115.005 6.63666C118.881 6.63666 123 8.89269 123 15.4733V16.6235H109.492C109.626 20.4087 111.938 22.4695 115.295 22.4695C117.536 22.4695 119.22 21.5493 119.947 19.7069L122.709 20.4435C121.837 23.1132 119.075 24.9072 115.295 24.9072C109.917 24.9072 106.622 21.2709 106.622 15.8386V15.8425ZM120.044 14.3056C120.044 11.313 118.057 9.10341 114.956 9.10341C111.685 9.10341 109.638 11.5547 109.444 14.3056H120.044Z" fill="#1D2939"/>
<path d="M70.2798 0V19.6779L70.0278 19.3319L55.8709 0H52.8356V24.5515H55.9368V4.87357L70.1441 24.5515H73.381V0H70.2798Z" fill="#1D2939"/>
<path d="M104.781 9.27932V6.9595H100.71V2.70648H97.9967V6.9595H95.0893V9.27932H97.8028V20.3662C97.8028 22.858 99.4872 24.3002 101.398 24.768C101.862 24.8821 102.336 24.9382 102.805 24.9382H104.779V22.2317H103.24C101.949 22.2317 100.708 21.8644 100.708 19.5678V9.27932H104.781Z" fill="#1D2939"/>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW 2018 (64-Bit) -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="210mm" height="39.6338mm" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 20999.98 3963.38"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<style type="text/css">
<![CDATA[
.fil0 {fill:#104DA9}
.fil1 {fill:#1D2939}
]]>
</style>
</defs>
<g id="Layer_x0020_1">
<metadata id="CorelCorpID_0Corel-Layer"/>
<g id="_1970686102672">
<path class="fil0" d="M6778.09 418.79c0,-226.11 186.87,-412.17 413.17,-412.17 226.31,0 415.1,186.06 415.1,412.17 0,226.1 -186.87,413.98 -415.1,413.98 -228.23,0 -413.17,-186.05 -413.17,-413.98z"/>
<polygon class="fil0" points="7606.36,1108.16 6778.09,1108.16 6778.09,3892.51 7606.36,3892.5 "/>
<path class="fil0" d="M1585.38 691.43c-406.48,0 -630.66,181.7 -630.66,429.29 -5.78,275.69 279.74,399.29 621.23,476.05l352.75 82.63c682.57,149.96 1175.25,489.22 1177.06,1128.7 -1.82,703.16 -565.37,1151.02 -1524.03,1151.02 -958.67,0 -1560.54,-429.6 -1581.73,-1260.01l803.13 0c26.67,384.28 337.44,579.16 768.76,579.16 431.32,0 693.93,-191.23 695.76,-472.39 -1.83,-258.85 -239.59,-378.81 -667.27,-480.1l-427.38 -104.94c-663.2,-155.34 -1071.51,-479.69 -1069.58,-1046.07 -3.75,-697.28 627.02,-1162.36 1487.43,-1162.36 860.41,0 1449.21,472.39 1460.87,1156.89l-795.43 0c-30.72,-301.64 -274.27,-477.96 -670.91,-477.96l0 0.09z"/>
<path class="fil0" d="M3473.51 2521.98c0,-853.93 549.75,-1439.58 1439.37,-1439.58 765.41,0 1278.87,422.51 1313.25,1065.94l-767.25 0c-43.91,-277.51 -234.62,-464.17 -532.52,-464.17 -377.89,0 -626.1,301.03 -626.1,826.75 0,525.72 246.39,835.88 626.1,835.88 278.52,0 484.66,-166.69 532.52,-464.18l767.24 0.01c-38.03,640.09 -528.87,1075.17 -1309.29,1075.17 -902.8,0 -1443.02,-589.3 -1443.02,-1435.92l-0.3 0 0 0.1z"/>
<path class="fil1" d="M12145.71 2521.07c0,-874.11 536.88,-1449.71 1334.43,-1449.71 797.55,0 1334.42,575.5 1334.42,1449.71 0,874.21 -536.87,1442.31 -1334.42,1442.31 -797.55,0 -1334.43,-575.5 -1334.43,-1442.31zm2216.45 0c0,-560.8 -276.1,-1063.5 -882.01,-1063.5 -605.92,0 -881.91,502.7 -881.91,1063.5 0,560.8 276.09,1056.21 881.91,1056.21 605.81,0 882.01,-495.41 882.01,-1056.21z"/>
<path class="fil1" d="M16875.17 2514.07c0,-859.5 529.06,-1457.01 1326.82,-1457.01 613.43,0 1265.38,357.1 1265.38,1398.61l0 182 -2137.97 0c21.2,599.13 387.12,925.21 918.42,925.21 354.67,0 621.23,-145.6 736.31,-437.21l437.11 116.6c-138,422.51 -575.2,706.51 -1173.42,706.51 -851.19,0 -1372.65,-575.5 -1372.65,-1435.31l0 0.61 0 -0.01zm2124.27 -243.24c0,-473.6 -314.52,-823.31 -805.27,-823.31 -517.71,0 -841.65,387.93 -872.38,823.31l1677.65 0z"/>
<polygon class="fil1" points="11123.27,6.63 11123.27,3121.11 11083.42,3066.36 8842.75,6.63 8362.35,6.63 8362.35,3892.41 8853.19,3892.4 8853.19,778.02 11101.78,3892.5 11614.11,3892.5 11614.11,6.63 "/>
<path class="fil1" d="M16583.86 1475.3l0 -367.15 -644.34 0.01 0 -673.15 -429.41 0 0 673.14 -460.11 0.01 0 367.15 429.49 -0.01 0 1754.7c0,394.42 266.57,622.65 569.02,696.67 73.41,18.05 148.44,26.97 222.66,26.97l312.39 0.01 0 -428.39 -243.54 0c-204.31,0 -400.71,-58.09 -400.71,-421.59l0 -1628.36 644.65 -0.01 -0.1 0z"/>
<path class="fil0" d="M20882.01 0l-655.26 0 -773.23 0 1546.46 1546.47 0 -1430.18c-5.5,-75.87 -54,-112.82 -117.97,-116.29z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

@ -68,10 +68,10 @@ RSpec.describe 'Api::V1::InventoryItemsController', type: :request do
inventory_id: @team1.repositories.first.id
), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
expect(hash_body[:data]).to match_array(
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@valid_inventory.repository_rows.limit(10),
.new(@valid_inventory.repository_rows.order(:id).limit(10),
each_serializer: Api::V1::InventoryItemSerializer,
include: :inventory_cells)
.to_json
@ -88,19 +88,19 @@ RSpec.describe 'Api::V1::InventoryItemsController', type: :request do
include: 'inventory_cells'
), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
expect(hash_body[:data]).to match_array(
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@valid_inventory.repository_rows.limit(10),
.new(@valid_inventory.repository_rows.order(:id).limit(10),
each_serializer: Api::V1::InventoryItemSerializer,
include: :inventory_cells)
.to_json
)['data']
)
expect(hash_body[:included]).to match(
expect(hash_body[:included]).to match_array(
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@valid_inventory.repository_rows.limit(10),
.new(@valid_inventory.repository_rows.order(:id).limit(10),
each_serializer: Api::V1::InventoryItemSerializer,
include: :inventory_cells)
.to_json
@ -115,7 +115,7 @@ RSpec.describe 'Api::V1::InventoryItemsController', type: :request do
inventory_id: @team1.repositories.first.id
), params: { page: { size: 100 } }, headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
expect(hash_body[:data]).to match_array(
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@valid_inventory.repository_rows.limit(100),

View file

@ -64,7 +64,6 @@ RSpec.describe 'Api::V1::ProtocolTemplateController', type: :request do
get api_v1_team_protocol_template_path(id: @protocol_published_original.id, team_id: @team.id), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
parsed_data = JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@protocol_published_original, serializer: Api::V1::ProtocolTemplateSerializer)