mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-09-20 14:45:56 +08:00
Add new stock management modal and edit itemm card stock fields [SCI-9415] (#6474)
* Add edit fetaure to item card stock field [SCI-9415] * Replace manage stock modal [SCI-9415] * Fix issue displaying item card [SCI-9415] * Minor improvements [SCI-9415] * Enable stock modal in assigned inventories [SCI-9415] * Use toggleable reminder value [SCI-9415]
This commit is contained in:
parent
7c54509c58
commit
c22d1e226b
|
@ -210,17 +210,18 @@ $.fn.dataTable.render.RepositoryStockValue = function(data) {
|
||||||
if (data) {
|
if (data) {
|
||||||
if (data.value) {
|
if (data.value) {
|
||||||
if (data.stock_managable) {
|
if (data.stock_managable) {
|
||||||
return `<a class="manage-repository-stock-value-link stock-value-view-render stock-${data.stock_status}">
|
return `<a class="manage-repository-stock-value-link stock-value-view-render stock-${data.stock_status}"
|
||||||
|
data-manage-stock-url=${data.value.stock_url}>
|
||||||
${data.value.stock_formatted}
|
${data.value.stock_formatted}
|
||||||
</a>`;
|
</a>`;
|
||||||
}
|
}
|
||||||
return `<span class="stock-value-view-render
|
return `<span class="stock-value-view-render data-manage-stock-url=${data.value.stock_url}
|
||||||
${data.displayWarnings ? `stock-${data.stock_status}` : ''}">
|
${data.displayWarnings ? `stock-${data.stock_status}` : ''}">
|
||||||
${data.value.stock_formatted}
|
${data.value.stock_formatted}
|
||||||
</span>`;
|
</span>`;
|
||||||
}
|
}
|
||||||
if (data.stock_managable) {
|
if (data.stock_managable) {
|
||||||
return `<a class="manage-repository-stock-value-link not-assigned-stock">
|
return `<a class="manage-repository-stock-value-link not-assigned-stock" data-manage-stock-url=${data.stock_url}>
|
||||||
<i class="fas fa-box-open"></i>
|
<i class="fas fa-box-open"></i>
|
||||||
${I18n.t('libraries.manange_modal_column.stock_type.add_stock')}
|
${I18n.t('libraries.manange_modal_column.stock_type.add_stock')}
|
||||||
</a>`;
|
</a>`;
|
||||||
|
|
|
@ -1,231 +0,0 @@
|
||||||
/* global dropdownSelector GLOBAL_CONSTANTS I18n SmartAnnotation formatDecimalValue Decimal */
|
|
||||||
|
|
||||||
var RepositoryStockValues = (function() {
|
|
||||||
const UNIT_SELECTOR = '#repository-stock-value-units';
|
|
||||||
|
|
||||||
function updateChangeAmount($element) {
|
|
||||||
if (!$element.val()) {
|
|
||||||
$('.stock-final-container .value').text('-');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!($element.val() >= 0)) return;
|
|
||||||
|
|
||||||
let currentAmount = new Decimal($element.data('currentAmount') || 0);
|
|
||||||
let inputAmount = new Decimal($element.val());
|
|
||||||
let newAmount;
|
|
||||||
|
|
||||||
switch ($element.data('operator')) {
|
|
||||||
case 'set':
|
|
||||||
newAmount = inputAmount;
|
|
||||||
break;
|
|
||||||
case 'add':
|
|
||||||
newAmount = currentAmount.plus(inputAmount);
|
|
||||||
break;
|
|
||||||
case 'remove':
|
|
||||||
newAmount = currentAmount.minus(inputAmount);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
newAmount = currentAmount;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$('#change_amount').val(inputAmount);
|
|
||||||
|
|
||||||
$('#repository_stock_value_amount').val(newAmount);
|
|
||||||
$('.stock-final-container').toggleClass('negative', newAmount < 0);
|
|
||||||
$('.stock-final-container .value').text(
|
|
||||||
formatDecimalValue(String(newAmount), $('#stock-input-amount').data('decimals'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function initManageAction() {
|
|
||||||
let amountChanged = false;
|
|
||||||
|
|
||||||
$('.repository-show').on('click', '.manage-repository-stock-value-link', function() {
|
|
||||||
let colIndex = this.parentNode.cellIndex;
|
|
||||||
let rowIndex = this.parentNode.parentNode.rowIndex;
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: $(this).closest('tr').data('manage-stock-url'),
|
|
||||||
type: 'GET',
|
|
||||||
dataType: 'json',
|
|
||||||
success: (result) => {
|
|
||||||
var $manageModal = $('#manage-repository-stock-value-modal');
|
|
||||||
$manageModal.find('.modal-content').html(result.html);
|
|
||||||
|
|
||||||
dropdownSelector.init(UNIT_SELECTOR, {
|
|
||||||
singleSelect: true,
|
|
||||||
closeOnSelect: true,
|
|
||||||
noEmptyOption: true,
|
|
||||||
selectAppearance: 'simple',
|
|
||||||
onChange: function() {
|
|
||||||
let unit = '';
|
|
||||||
if (dropdownSelector.getValues(UNIT_SELECTOR) > 0) {
|
|
||||||
unit = dropdownSelector.getLabels(UNIT_SELECTOR);
|
|
||||||
}
|
|
||||||
$('.stock-final-container .units').text(unit);
|
|
||||||
$('.repository-stock-reminder-value .units').text(
|
|
||||||
I18n.t('repository_stock_values.manage_modal.units_remaining', {
|
|
||||||
unit: unit
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$manageModal.find(`
|
|
||||||
.dropdown-selector-container .input-field,
|
|
||||||
.dropdown-selector-container .search-field
|
|
||||||
`).attr('tabindex', 2);
|
|
||||||
|
|
||||||
$manageModal.find('form').on('ajax:success', function(_, data) {
|
|
||||||
$manageModal.modal('hide');
|
|
||||||
let $cell = $('.dataTable').find(
|
|
||||||
`tr:nth-child(${rowIndex}) td:nth-child(${colIndex + 1})`
|
|
||||||
);
|
|
||||||
$cell.parent().data('manage-stock-url', data.manageStockUrl);
|
|
||||||
$cell.html(
|
|
||||||
$.fn.dataTable.render.RepositoryStockValue(data)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.stock-operator-option').click(function() {
|
|
||||||
var $stockInput = $('#stock-input-amount');
|
|
||||||
$('.stock-operator-option').removeClass('btn-primary').addClass('btn-secondary');
|
|
||||||
$(this).removeClass('btn-secondary').addClass('btn-primary');
|
|
||||||
$stockInput.data('operator', $(this).data('operator'));
|
|
||||||
|
|
||||||
dropdownSelector.selectValues(UNIT_SELECTOR, $('#initial_units').val());
|
|
||||||
$('#operator').val($(this).data('operator'));
|
|
||||||
switch ($(this).data('operator')) {
|
|
||||||
case 'set':
|
|
||||||
dropdownSelector.enableSelector(UNIT_SELECTOR);
|
|
||||||
if (!amountChanged) { $stockInput.val($stockInput.data('currentAmount')); }
|
|
||||||
break;
|
|
||||||
case 'add':
|
|
||||||
if (!amountChanged) { $stockInput.val(''); }
|
|
||||||
dropdownSelector.disableSelector(UNIT_SELECTOR);
|
|
||||||
break;
|
|
||||||
case 'remove':
|
|
||||||
if (!amountChanged) { $stockInput.val(''); }
|
|
||||||
dropdownSelector.disableSelector(UNIT_SELECTOR);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateChangeAmount($('#stock-input-amount'));
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#stock-input-amount, #low_stock_threshold').on('input focus', function() {
|
|
||||||
let decimals = $(this).data('decimals');
|
|
||||||
this.value = formatDecimalValue(this.value, decimals);
|
|
||||||
});
|
|
||||||
|
|
||||||
SmartAnnotation.init($('#repository-stock-value-comment')[0], false);
|
|
||||||
|
|
||||||
$('#repository-stock-value-comment').on('input', function() {
|
|
||||||
$(this).closest('.sci-input-container').toggleClass(
|
|
||||||
'error',
|
|
||||||
this.value.length > GLOBAL_CONSTANTS.NAME_MAX_LENGTH
|
|
||||||
);
|
|
||||||
$('.update-repository-stock').toggleClass(
|
|
||||||
'disabled',
|
|
||||||
this.value.length > GLOBAL_CONSTANTS.NAME_MAX_LENGTH
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#reminder-selector-checkbox').on('change', function() {
|
|
||||||
let valueContainer = $('.repository-stock-reminder-value');
|
|
||||||
valueContainer.toggleClass('hidden', !this.checked);
|
|
||||||
if (!this.checked) {
|
|
||||||
$(this).data('reminder-value', valueContainer.find('input').val());
|
|
||||||
valueContainer.find('input').val(null);
|
|
||||||
} else {
|
|
||||||
valueContainer.find('input').val($(this).data('reminder-value'));
|
|
||||||
valueContainer.find('input').focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.update-repository-stock').on('click', function() {
|
|
||||||
let reminderError = $('#reminder-selector-checkbox')[0].checked
|
|
||||||
&& $('.repository-stock-reminder-value').find('input').val() === '';
|
|
||||||
$('.repository-stock-reminder-value').find('.sci-input-container').toggleClass('error', reminderError);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#stock-input-amount').on('input', function() {
|
|
||||||
amountChanged = true;
|
|
||||||
updateChangeAmount($(this));
|
|
||||||
});
|
|
||||||
|
|
||||||
$manageModal.on('ajax:beforeSend', 'form', function() {
|
|
||||||
let status = true;
|
|
||||||
if (!(dropdownSelector.getValues(UNIT_SELECTOR) > 0)) {
|
|
||||||
dropdownSelector.showError(UNIT_SELECTOR, I18n.t('repository_stock_values.manage_modal.unit_error'));
|
|
||||||
status = false;
|
|
||||||
} else {
|
|
||||||
dropdownSelector.hideError(UNIT_SELECTOR);
|
|
||||||
}
|
|
||||||
let stockInput = $('#stock-input-amount');
|
|
||||||
if (stockInput.val().length && stockInput.val() >= 0) {
|
|
||||||
stockInput.parent().removeClass('error');
|
|
||||||
} else {
|
|
||||||
stockInput.parent().addClass('error');
|
|
||||||
if (stockInput.val().length === 0) {
|
|
||||||
stockInput.parent()
|
|
||||||
.attr(
|
|
||||||
'data-error-text',
|
|
||||||
I18n.t('repository_stock_values.manage_modal.amount_error')
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
stockInput.parent()
|
|
||||||
.attr(
|
|
||||||
'data-error-text',
|
|
||||||
I18n.t('repository_stock_values.manage_modal.negative_error')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
status = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let reminderInput = $('.repository-stock-reminder-value input');
|
|
||||||
if ($('#reminder-selector-checkbox')[0].checked) {
|
|
||||||
if (reminderInput.val().length && reminderInput.val() >= 0) {
|
|
||||||
reminderInput.parent().removeClass('error');
|
|
||||||
} else {
|
|
||||||
reminderInput.parent().addClass('error');
|
|
||||||
if (reminderInput.val().length === 0) {
|
|
||||||
reminderInput.parent()
|
|
||||||
.attr(
|
|
||||||
'data-error-text',
|
|
||||||
I18n.t('repository_stock_values.manage_modal.amount_error')
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
reminderInput.parent()
|
|
||||||
.attr(
|
|
||||||
'data-error-text',
|
|
||||||
I18n.t('repository_stock_values.manage_modal.negative_error')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
status = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
});
|
|
||||||
|
|
||||||
$manageModal.modal('show');
|
|
||||||
amountChanged = false;
|
|
||||||
$('#stock-input-amount').focus();
|
|
||||||
$('#stock-input-amount')[0].selectionStart = $('#stock-input-amount')[0].value.length;
|
|
||||||
$('#stock-input-amount')[0].selectionEnd = $('#stock-input-amount')[0].value.length;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
init: () => {
|
|
||||||
initManageAction();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}());
|
|
||||||
|
|
||||||
RepositoryStockValues.init();
|
|
|
@ -69,4 +69,24 @@
|
||||||
$('#modal-info-repository-row').modal('hide');
|
$('#modal-info-repository-row').modal('hide');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$(document).on('click', '.manage-repository-stock-value-link', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
window.initManageStockValueModalComponent();
|
||||||
|
if (window.manageStockModalComponent) {
|
||||||
|
const $link = $(e.target).parents('a')[0] ? $(e.target).parents('a') : $(e.target);
|
||||||
|
const stockValueUrl = $link.data('manage-stock-url');
|
||||||
|
let updateCallback;
|
||||||
|
if (stockValueUrl) {
|
||||||
|
updateCallback = (data) => {
|
||||||
|
if (!data?.value) return;
|
||||||
|
// reload dataTable
|
||||||
|
if ($('.dataTable')[0]) $('.dataTable').DataTable().ajax.reload();
|
||||||
|
// update item card stock column
|
||||||
|
window.manageStockCallback && window.manageStockCallback(data.value)
|
||||||
|
};
|
||||||
|
window.manageStockModalComponent.showModal(stockValueUrl, updateCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -43,6 +43,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
border-color: var(--sn-delete-red);
|
||||||
|
}
|
||||||
|
|
||||||
.sn-select__options {
|
.sn-select__options {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,16 @@
|
||||||
|
/* Hide arrows on number type input field */
|
||||||
|
@layer utilities {
|
||||||
|
input[type="number"]::-webkit-inner-spin-button,
|
||||||
|
input[type="number"]::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=number] {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
.sci-btn-group {
|
.sci-btn-group {
|
||||||
@apply inline-flex items-center gap-2 relative;
|
@apply inline-flex items-center gap-2 relative;
|
||||||
|
|
|
@ -6,33 +6,9 @@ class RepositoryStockValuesController < ApplicationController
|
||||||
before_action :load_vars
|
before_action :load_vars
|
||||||
before_action :check_manage_permissions
|
before_action :check_manage_permissions
|
||||||
|
|
||||||
def new
|
def new; end
|
||||||
render json: {
|
|
||||||
html: render_to_string(
|
|
||||||
partial: 'repository_stock_values/manage_modal_content',
|
|
||||||
locals: {
|
|
||||||
repository_row: @repository_row,
|
|
||||||
repository_stock_column: @repository_column,
|
|
||||||
unit_items: @repository_column.repository_stock_unit_items,
|
|
||||||
repository_stock_value: RepositoryStockValue.new
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def edit
|
def edit; end
|
||||||
render json: {
|
|
||||||
html: render_to_string(
|
|
||||||
partial: 'repository_stock_values/manage_modal_content',
|
|
||||||
locals: {
|
|
||||||
repository_row: @repository_row,
|
|
||||||
repository_stock_column: @repository_column,
|
|
||||||
unit_items: @repository_column.repository_stock_unit_items,
|
|
||||||
repository_stock_value: @repository_stock_value
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_or_update
|
def create_or_update
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
|
@ -50,8 +26,12 @@ class RepositoryStockValuesController < ApplicationController
|
||||||
render json: {
|
render json: {
|
||||||
stock_managable: true,
|
stock_managable: true,
|
||||||
stock_status: @repository_stock_value.status,
|
stock_status: @repository_stock_value.status,
|
||||||
manageStockUrl: edit_repository_stock_repository_repository_row_url(@repository, @repository_row)
|
}.merge(
|
||||||
}.merge(serialize_repository_cell_value(@repository_stock_value.repository_cell, current_team, @repository))
|
serialize_repository_cell_value(
|
||||||
|
@repository_stock_value.repository_cell, current_team, @repository,
|
||||||
|
reminders_enabled: Repository.reminders_enabled?
|
||||||
|
)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
module RepositoryDatatableHelper
|
module RepositoryDatatableHelper
|
||||||
include InputSanitizeHelper
|
include InputSanitizeHelper
|
||||||
|
include Rails.application.routes.url_helpers
|
||||||
|
|
||||||
def prepare_row_columns(repository_rows, repository, columns_mappings, team, options = {})
|
def prepare_row_columns(repository_rows, repository, columns_mappings, team, options = {})
|
||||||
has_stock_management = repository.has_stock_management?
|
has_stock_management = repository.has_stock_management?
|
||||||
|
@ -47,20 +48,6 @@ module RepositoryDatatableHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
if has_stock_management
|
if has_stock_management
|
||||||
row['manageStockUrl'] = if record.has_stock?
|
|
||||||
Rails.application.routes.url_helpers
|
|
||||||
.edit_repository_stock_repository_repository_row_url(
|
|
||||||
repository,
|
|
||||||
record
|
|
||||||
)
|
|
||||||
else
|
|
||||||
Rails.application.routes.url_helpers
|
|
||||||
.new_repository_stock_repository_repository_row_url(
|
|
||||||
repository,
|
|
||||||
record
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
stock_cell = record.repository_cells.find { |cell| cell.value_type == 'RepositoryStockValue' }
|
stock_cell = record.repository_cells.find { |cell| cell.value_type == 'RepositoryStockValue' }
|
||||||
|
|
||||||
# always add stock cell, even if empty
|
# always add stock cell, even if empty
|
||||||
|
@ -68,7 +55,7 @@ module RepositoryDatatableHelper
|
||||||
if stock_cell.present?
|
if stock_cell.present?
|
||||||
serialize_repository_cell_value(record.repository_stock_cell, team, repository)
|
serialize_repository_cell_value(record.repository_stock_cell, team, repository)
|
||||||
else
|
else
|
||||||
{}
|
{ stock_url: new_repository_stock_repository_repository_row_url(repository, record) }
|
||||||
end
|
end
|
||||||
row['stock'][:stock_managable] = stock_managable
|
row['stock'][:stock_managable] = stock_managable
|
||||||
row['stock']['displayWarnings'] = display_stock_warnings?(repository)
|
row['stock']['displayWarnings'] = display_stock_warnings?(repository)
|
||||||
|
|
24
app/javascript/packs/vue/manage_stock_value_modal.js
Normal file
24
app/javascript/packs/vue/manage_stock_value_modal.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import TurbolinksAdapter from 'vue-turbolinks';
|
||||||
|
import Vue from 'vue/dist/vue.esm';
|
||||||
|
import PerfectScrollbar from 'vue2-perfect-scrollbar';
|
||||||
|
import 'vue2-perfect-scrollbar/dist/vue2-perfect-scrollbar.css';
|
||||||
|
import ManageStockValueModal from '../../vue/repository_row/manage_stock_value_modal.vue';
|
||||||
|
|
||||||
|
Vue.use(PerfectScrollbar);
|
||||||
|
Vue.use(TurbolinksAdapter);
|
||||||
|
Vue.prototype.i18n = window.I18n;
|
||||||
|
|
||||||
|
window.initManageStockValueModalComponent = () => {
|
||||||
|
if (window.manageStockModalComponent) return;
|
||||||
|
|
||||||
|
if (notTurbolinksPreview()) {
|
||||||
|
new Vue({
|
||||||
|
el: '#manageStockValueModal',
|
||||||
|
components: {
|
||||||
|
'manage-stock-value-modal': ManageStockValueModal,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
initManageStockValueModalComponent();
|
|
@ -1,12 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="customColumns?.length > 0" class="flex flex-col gap-4 w-[350px] h-auto">
|
<div v-if="customColumns?.length > 0" class="flex flex-col gap-4 w-[350px] h-auto">
|
||||||
<div v-for="(column, index) in customColumns" :key="column.id" class="flex flex-col gap-4 w-[350px] h-auto relative">
|
<div v-for="(column, index) in customColumns" :key="column.id" class="flex flex-col gap-4 w-[350px] h-auto relative">
|
||||||
<span class="absolute right-2 top-6" v-if="column?.value?.reminder === true">
|
|
||||||
<Reminder :value="column?.value" :valueType="column?.value_type" />
|
|
||||||
</span>
|
|
||||||
<component
|
<component
|
||||||
:is="column.data_type"
|
:is="column.data_type"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
:actions="actions"
|
||||||
:data_type="column.data_type"
|
:data_type="column.data_type"
|
||||||
:colId="column.id"
|
:colId="column.id"
|
||||||
:colName="column.name"
|
:colName="column.name"
|
||||||
|
@ -18,7 +16,6 @@
|
||||||
:optionsPath="column.options_path"
|
:optionsPath="column.options_path"
|
||||||
:inArchivedRepositoryRow="inArchivedRepositoryRow"
|
:inArchivedRepositoryRow="inArchivedRepositoryRow"
|
||||||
:editingField="editingField"
|
:editingField="editingField"
|
||||||
:actions="actions"
|
|
||||||
@setEditingField="editingField = $event"
|
@setEditingField="editingField = $event"
|
||||||
@update="update"
|
@update="update"
|
||||||
/>
|
/>
|
||||||
|
@ -31,7 +28,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Reminder from './reminder.vue'
|
|
||||||
import RepositoryStockValue from './repository_values/RepositoryStockValue.vue';
|
import RepositoryStockValue from './repository_values/RepositoryStockValue.vue';
|
||||||
import RepositoryTextValue from './repository_values/RepositoryTextValue.vue';
|
import RepositoryTextValue from './repository_values/RepositoryTextValue.vue';
|
||||||
import RepositoryNumberValue from './repository_values/RepositoryNumberValue.vue';
|
import RepositoryNumberValue from './repository_values/RepositoryNumberValue.vue';
|
||||||
|
@ -49,7 +45,6 @@
|
||||||
export default {
|
export default {
|
||||||
name: 'CustomColumns',
|
name: 'CustomColumns',
|
||||||
components: {
|
components: {
|
||||||
Reminder,
|
|
||||||
RepositoryStockValue,
|
RepositoryStockValue,
|
||||||
RepositoryTextValue,
|
RepositoryTextValue,
|
||||||
RepositoryNumberValue,
|
RepositoryNumberValue,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<template v-if="value.reminder === true">
|
<template v-if="value?.reminder === true">
|
||||||
<div class="inline-block float-right cursor-pointer relative" :title="reminderTitle"
|
<div class="inline-block float-right cursor-pointer relative" :title="reminderTitle"
|
||||||
tabindex='-1'>
|
tabindex='-1'>
|
||||||
<i class="sn-icon sn-icon-notifications row-reminders-icon"></i>
|
<i class="sn-icon sn-icon-notifications row-reminders-icon"></i>
|
||||||
|
@ -14,14 +14,14 @@
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
reminderColor() {
|
reminderColor() {
|
||||||
if (this.value.reminder && (this.value.stock_amount > 0 || this.value.days_left > 0)) {
|
if (this.value?.reminder && (this.value?.stock_amount > 0 || this.value?.days_left > 0)) {
|
||||||
return 'bg-sn-alert-brittlebush';
|
return 'bg-sn-alert-brittlebush';
|
||||||
}
|
}
|
||||||
return 'bg-sn-alert-passion';
|
return 'bg-sn-alert-passion';
|
||||||
},
|
},
|
||||||
reminderTitle() {
|
reminderTitle() {
|
||||||
let title = this.value.reminder_text
|
let title = this.value?.reminder_text
|
||||||
if (this.value.reminder_message) title = `${title}\n${this.value.reminder_message}`;
|
if (this.value?.reminder_message) title = `${title}\n${this.value?.reminder_message}`;
|
||||||
|
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,40 +8,81 @@
|
||||||
{{ i18n.t('repositories.item_card.stock_export') }}
|
{{ i18n.t('repositories.item_card.stock_export') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="colVal?.stock_formatted" class="text-sn-dark-grey font-inter text-sm font-normal leading-5">
|
<a style="text-decoration: none;"
|
||||||
{{ colVal?.stock_formatted }}
|
class="text-sn-dark-grey font-inter text-sm font-normal leading-5 w-full rounded relative block"
|
||||||
</div>
|
:class="editableClassName"
|
||||||
<div v-else class="text-sn-dark-grey font-inter text-sm font-normal leading-5">
|
@click="enableEditing"
|
||||||
{{ i18n.t('repositories.item_card.repository_stock_value.no_stock') }}
|
:data-manage-stock-url="stockValueUrl"
|
||||||
</div>
|
:data-repository-row-id="repositoryId"
|
||||||
|
>
|
||||||
|
<div v-if="values?.stock_formatted" class="text-sn-dark-grey font-inter text-sm font-normal leading-5 stock-value">
|
||||||
|
{{ values.stock_formatted }}
|
||||||
|
</div>
|
||||||
|
<div v-else class="text-sn-dark-grey font-inter text-sm font-normal leading-5 stock-value">
|
||||||
|
{{ i18n.t('repositories.item_card.repository_stock_value.no_stock') }}
|
||||||
|
</div>
|
||||||
|
<span class="absolute right-2 reminder" :class="{ 'top-1.5': permissions?.can_manage, 'top-0': !permissions?.can_manage, hidden: !values?.reminder }">
|
||||||
|
<Reminder :value="values" />
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
import Reminder from '../reminder.vue';
|
||||||
name: 'RepositoryStockValue',
|
export default {
|
||||||
data() {
|
name: 'RepositoryStockValue',
|
||||||
return {
|
components: {
|
||||||
stock_formatted: null,
|
Reminder
|
||||||
stock_amount: null,
|
},
|
||||||
low_stock_threshold: null
|
computed: {
|
||||||
|
editableClassName() {
|
||||||
|
const className = 'border-solid border-[1px] p-2 manage-repository-stock-value-link sci-cursor-edit'
|
||||||
|
if (this.permissions.can_manage && this.isEditing) return `${className} border-sn-science-blue`;
|
||||||
|
if (this.permissions.can_manage) return `${className} border-sn-light-grey hover:border-sn-sleepy-grey`;
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
stock_formatted: null,
|
||||||
|
stock_amount: null,
|
||||||
|
low_stock_threshold: null,
|
||||||
|
isEditing: null,
|
||||||
|
values: null,
|
||||||
|
stockValueUrl: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
data_type: String,
|
||||||
|
colId: Number,
|
||||||
|
colName: String,
|
||||||
|
colVal: Object,
|
||||||
|
repositoryId: Number,
|
||||||
|
repositoryRowId: null,
|
||||||
|
permissions: null,
|
||||||
|
actions: null,
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.values = this.colVal;
|
||||||
|
this.stockValueUrl = this.actions.stock.stock_value_url
|
||||||
|
window.manageStockCallback = this.submitCallback;
|
||||||
|
},
|
||||||
|
unmounted(){
|
||||||
|
delete window.manageStockCallback
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
enableEditing(){
|
||||||
|
this.isEditing = true
|
||||||
|
const $this = this;
|
||||||
|
// disable edit
|
||||||
|
$('#manageStockValueModal').on('hide.bs.modal', function() {
|
||||||
|
$this.isEditing = false;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
submitCallback(values) {
|
||||||
|
if (values) this.values = values;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
props: {
|
|
||||||
data_type: String,
|
|
||||||
colId: Number,
|
|
||||||
colName: String,
|
|
||||||
colVal: Object,
|
|
||||||
repositoryId: Number,
|
|
||||||
repositoryRowId: null,
|
|
||||||
permissions: null
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
if (!this.colVal) return
|
|
||||||
|
|
||||||
this.stock_formatted = this.colVal.stock_formatted
|
|
||||||
this.stock_amount = this.colVal.stock_amount
|
|
||||||
this.low_stock_threshold = this.colVal.low_stock_threshold
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
278
app/javascript/vue/repository_row/manage_stock_value_modal.vue
Normal file
278
app/javascript/vue/repository_row/manage_stock_value_modal.vue
Normal file
|
@ -0,0 +1,278 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
ref="modal"
|
||||||
|
class="modal fade"
|
||||||
|
tabindex="-1"
|
||||||
|
role="dialog"
|
||||||
|
aria-labelledby="manage-stock-value"
|
||||||
|
>
|
||||||
|
<div class="modal-dialog" role="document" v-if="stockValue">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" :aria-label="i18n.t('general.close')">
|
||||||
|
<i class="sn-icon sn-icon-close"></i>
|
||||||
|
</button>
|
||||||
|
<h4 class="modal-title">
|
||||||
|
<template v-if="!!stockValue?.id">
|
||||||
|
{{ i18n.t('repository_stock_values.manage_modal.title', { item: repositoryRowName }) }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ i18n.t('repository_stock_values.manage_modal.edit_title', { item: repositoryRowName }) }}
|
||||||
|
</template>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p class="text-sm pb-6"> {{ i18n.t('repository_stock_values.manage_modal.enter_amount') }}</p>
|
||||||
|
<form class="flex flex-col gap-6" @submit.prevent novalidate>
|
||||||
|
<fieldset class="w-full flex justify-between">
|
||||||
|
<div class="flex flex-col w-40">
|
||||||
|
<label class="text-sn-grey text-sm font-normal" for="operations">{{ i18n.t('repository_stock_values.manage_modal.operation') }}</label>
|
||||||
|
<Select
|
||||||
|
:disabled="!stockValue?.id"
|
||||||
|
:value="operation"
|
||||||
|
:options="operations"
|
||||||
|
@change="setOperation"
|
||||||
|
></Select>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col w-40">
|
||||||
|
<Input
|
||||||
|
@input="amount = $event"
|
||||||
|
name="stock_amount"
|
||||||
|
id="stock-amount"
|
||||||
|
:inputClass="`sci-input-container-v2 ${errors.amount ? 'error' : ''}`"
|
||||||
|
:labelClass="`text-sm font-normal ${errors.amount ? 'text-sn-delete-red' : 'text-sn-grey'}`"
|
||||||
|
type="number"
|
||||||
|
:value="amount"
|
||||||
|
:decimals="stockValue.decimals"
|
||||||
|
:placeholder="i18n.t('repository_stock_values.manage_modal.amount_placeholder_new')"
|
||||||
|
required
|
||||||
|
:label="i18n.t('repository_stock_values.manage_modal.amount')"
|
||||||
|
showLabel
|
||||||
|
autoFocus
|
||||||
|
:error="errors.amount"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col w-40">
|
||||||
|
<label :class="`text-sm font-normal ${errors.unit ? 'text-sn-delete-red' : 'text-sn-grey'}`" for="stock-unit">
|
||||||
|
{{ i18n.t('repository_stock_values.manage_modal.unit') }}
|
||||||
|
</label>
|
||||||
|
<Select
|
||||||
|
:disabled="[2, 3].includes(operation)"
|
||||||
|
:value="unit"
|
||||||
|
:options="units"
|
||||||
|
:placeholder="i18n.t('repository_stock_values.manage_modal.unit_prompt')"
|
||||||
|
@change="unit = $event"
|
||||||
|
:className="`${errors.unit ? 'error' : ''}`"
|
||||||
|
></Select>
|
||||||
|
<div class="text-sn-delete-red text-xs" :class="{ visible: errors.unit, invisible: !errors.unit }">
|
||||||
|
{{ errors.unit }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<template v-if="stockValue?.id">
|
||||||
|
<div class="flex justify-between w-full items-center">
|
||||||
|
<div class="flex flex-col w-[220px] h-24 border-rounded bg-sn-super-light-grey justify-between text-center">
|
||||||
|
<span class="text-sm text-sn-grey leading-5">{{ i18n.t('repository_stock_values.manage_modal.current_stock') }}</span>
|
||||||
|
<span class="text-2xl text-sn-black font-semibold leading-8" :class="{ 'text-sn-delete-red': stockValue.amount < 0 }">{{ stockValue.amount }}</span>
|
||||||
|
<span class="text-sm text0sn-black leading-5">{{ initUnitLabel }}</span>
|
||||||
|
</div>
|
||||||
|
<i class="sn-icon sn-icon-arrow-right"></i>
|
||||||
|
<div class="flex flex-col w-[220px] h-24 border-rounded bg-sn-super-light-grey justify-between text-center">
|
||||||
|
<span class="text-sm text-sn-grey leading-5">{{ i18n.t('repository_stock_values.manage_modal.new_stock') }}</span>
|
||||||
|
<span class="text-2xl text-sn-black font-semibold leading-8" :class="{ 'text-sn-delete-red': newAmount < 0 }">
|
||||||
|
{{ (newAmount || newAmount === 0) ? newAmount : '-' }}
|
||||||
|
</span>
|
||||||
|
<span class="text-sm text0sn-black leading-5">{{ unitLabel }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="repository-stock-reminder-selector">
|
||||||
|
<div class="sci-checkbox-container">
|
||||||
|
<input type="checkbox" name="reminder-enabled" tabindex="4" class="sci-checkbox" id="reminder-selector-checkbox" :checked="reminderEnabled" @change="reminderEnabled = $event.target.checked"/>
|
||||||
|
<span class="sci-checkbox-label"></span>
|
||||||
|
</div>
|
||||||
|
<span class="ml-2">{{ i18n.t('repository_stock_values.manage_modal.create_reminder') }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="reminderEnabled" class="stock-reminder-value flex gap-2 items-center">
|
||||||
|
<Input
|
||||||
|
@input="lowStockTreshold = $event"
|
||||||
|
name="treshold_amount"
|
||||||
|
id="treshold-amount"
|
||||||
|
fieldClass="flex gap-2"
|
||||||
|
inputClass="sci-input-container-v2 w-40"
|
||||||
|
labelClass="text-sm font-normal flex items-center"
|
||||||
|
type="number"
|
||||||
|
:value="lowStockTreshold"
|
||||||
|
:decimals="stockValue.decimals"
|
||||||
|
:placeholder="i18n.t('repository_stock_values.manage_modal.amount_placeholder_new')"
|
||||||
|
required
|
||||||
|
:label="i18n.t('repository_stock_values.manage_modal.reminder_at')"
|
||||||
|
showLabel
|
||||||
|
:error="errors.tresholdAmount"
|
||||||
|
/>
|
||||||
|
<span class="text-sm font-normal">
|
||||||
|
{{ unitLabel }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="sci-input-container flex flex-col" :data-error-text="i18n.t('repository_stock_values.manage_modal.comment_limit')">
|
||||||
|
<label class="text-sn-grey text-sm font-normal" for="stock-value-comment">{{ i18n.t('repository_stock_values.manage_modal.comment') }}</label>
|
||||||
|
<input class="sci-input-field"
|
||||||
|
@input="comment = e.target.value"
|
||||||
|
type="text"
|
||||||
|
name="comment"
|
||||||
|
id="stock-value-comment"
|
||||||
|
:placeholder="i18n.t('repository_stock_values.manage_modal.comment_placeholder')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type='button' class='btn btn-secondary' data-dismiss='modal'>
|
||||||
|
{{ i18n.t('general.cancel') }}
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary" @click="validateAndsaveStockValue">
|
||||||
|
{{ i18n.t('repository_stock_values.manage_modal.save_stock') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Select from './../shared/select.vue';
|
||||||
|
import Input from './../shared/input.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ManageStockValueModal',
|
||||||
|
components: {
|
||||||
|
Select,
|
||||||
|
Input
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
operation: null,
|
||||||
|
operations: [],
|
||||||
|
stockValue: null,
|
||||||
|
amount: 0,
|
||||||
|
repositoryRowName: null,
|
||||||
|
stockUrl: null,
|
||||||
|
units: null,
|
||||||
|
unit: null,
|
||||||
|
reminderEnabled: false,
|
||||||
|
lowStockTreshold: null,
|
||||||
|
comment: null,
|
||||||
|
errors: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
unitLabel: function() {
|
||||||
|
const currentUnit = this.units?.find(option => option[0] === this.unit);
|
||||||
|
return currentUnit ? currentUnit[1] : ''
|
||||||
|
},
|
||||||
|
initUnitLabel: function() {
|
||||||
|
const unit = this.units?.find(option => option[0] === this.stockValue?.unit);
|
||||||
|
return unit ? unit[1] : ''
|
||||||
|
},
|
||||||
|
newAmount: function() {
|
||||||
|
switch (this.operation) {
|
||||||
|
case 2:
|
||||||
|
if (this.amount) return parseFloat(this.stockValue.amount) + this.amount
|
||||||
|
case 3:
|
||||||
|
if(this.amount) return parseFloat(this.stockValue.amount) - this.amount
|
||||||
|
default:
|
||||||
|
return this.amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
window.manageStockModalComponent = this;
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
delete window.manageStockModalComponent;
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// Focus stock amount input field
|
||||||
|
$(this.$refs.modal).on('show.bs.modal', function() {
|
||||||
|
setTimeout(() => {
|
||||||
|
$('#stock-amount')[0]?.focus()
|
||||||
|
}, 500)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setOperation($event) {
|
||||||
|
this.operation = $event;
|
||||||
|
if ([2, 3].includes($event)) {
|
||||||
|
this.unit = this.stockValue.unit;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchStockValueData(stockValueUrl) {
|
||||||
|
if (!stockValueUrl) return;
|
||||||
|
$.ajax({
|
||||||
|
method: 'GET',
|
||||||
|
url: stockValueUrl,
|
||||||
|
dataType: 'json',
|
||||||
|
success: (result) => {
|
||||||
|
this.repositoryRowName = result.repository_row_name
|
||||||
|
this.stockValue = result.stock_value
|
||||||
|
this.amount = parseFloat(result.stock_value.amount)
|
||||||
|
this.units = result.stock_value.units
|
||||||
|
this.unit = result.stock_value.unit
|
||||||
|
this.reminderEnabled = result.stock_value.reminder_enabled
|
||||||
|
this.lowStockTreshold = result.stock_value.low_stock_treshold
|
||||||
|
this.operation = 1;
|
||||||
|
this.stockUrl = result.stock_url;
|
||||||
|
this.operations = [[1, 'set'], [2, 'add'], [3, 'remove']];
|
||||||
|
this.errors = {};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
closeModal() {
|
||||||
|
$(this.$refs.modal).modal('hide');
|
||||||
|
},
|
||||||
|
showModal(stockValueUrl, closeCallback) {
|
||||||
|
$(this.$refs.modal).modal('show');
|
||||||
|
this.fetchStockValueData(stockValueUrl);
|
||||||
|
this.closeCallback = closeCallback;
|
||||||
|
},
|
||||||
|
validateAndsaveStockValue() {
|
||||||
|
let newErrors = {};
|
||||||
|
this.errors = newErrors;
|
||||||
|
if (!this.unit)
|
||||||
|
newErrors['unit'] = I18n.t('repository_stock_values.manage_modal.unit_error');
|
||||||
|
if (!this.amount)
|
||||||
|
newErrors['amount'] = I18n.t('repository_stock_values.manage_modal.amount_error');
|
||||||
|
if (parseFloat(this.amount) && this.amount < 0)
|
||||||
|
newErrors['amount'] = I18n.t('repository_stock_values.manage_modal.negative_error');
|
||||||
|
if (this.reminderEnabled && !this.lowStockTreshold)
|
||||||
|
newErrors['tresholdAmount'] = I18n.t('repository_stock_values.manage_modal.amount_error');
|
||||||
|
|
||||||
|
this.errors = newErrors;
|
||||||
|
|
||||||
|
if (!$.isEmptyObject(newErrors)) return;
|
||||||
|
|
||||||
|
const $this = this
|
||||||
|
$.ajax({
|
||||||
|
method: 'POST',
|
||||||
|
url: this.stockUrl,
|
||||||
|
dataType: 'json',
|
||||||
|
data: {
|
||||||
|
repository_stock_value: {
|
||||||
|
unit_item_id: this.unit,
|
||||||
|
amount: this.newAmount,
|
||||||
|
comment: this.comment,
|
||||||
|
low_stock_threshold: this.reminderEnabled ? this.lowStockTreshold : null
|
||||||
|
},
|
||||||
|
operator: this.operations.find(operation => operation[0] = this.operation)?.[1],
|
||||||
|
change_amount: Math.abs(this.amount),
|
||||||
|
},
|
||||||
|
success: function(result) {
|
||||||
|
$this.stockValue = null;
|
||||||
|
$this.closeModal();
|
||||||
|
$this.closeCallback && $this.closeCallback(result);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
73
app/javascript/vue/shared/input.vue
Normal file
73
app/javascript/vue/shared/input.vue
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<template>
|
||||||
|
<div class="relative" :class="fieldClass">
|
||||||
|
<label v-if="showLabel" :class="labelClass" :for="id">{{ label }}</label>
|
||||||
|
<div :class="inputClass">
|
||||||
|
<input ref="input"
|
||||||
|
:id="id"
|
||||||
|
:type="type"
|
||||||
|
:name="name"
|
||||||
|
:value="value"
|
||||||
|
:class="`${error ? 'error' : ''}`"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:required="required"
|
||||||
|
@input="updateValue"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="mt-2 text-sn-delete-red whitespace-nowrap truncate text-xs font-normal absolute bottom-[-1rem] w-full"
|
||||||
|
:title="error"
|
||||||
|
:class="{ visible: error, invisible: !error}"
|
||||||
|
>
|
||||||
|
{{ error }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Input',
|
||||||
|
props: {
|
||||||
|
id: { type: String, required: false },
|
||||||
|
fieldClass: { type: String, default: '' },
|
||||||
|
inputClass: { type: String, default: '' },
|
||||||
|
labelClass: { type: String, default: '' },
|
||||||
|
type: { type: String, default: 'text' },
|
||||||
|
name: { type: String, required: true },
|
||||||
|
value: { type: [String, Number], required: false },
|
||||||
|
decimals: { type: [Number, String], default: 0 },
|
||||||
|
placeholder: { type: String, default: '' },
|
||||||
|
required: { type: Boolean, default: false },
|
||||||
|
showLabel: { type: Boolean, default: false },
|
||||||
|
label: { type: String, required: false },
|
||||||
|
autoFocus: { type: Boolean, default: false },
|
||||||
|
error: { type: String, required: false }
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: function(newVal) {
|
||||||
|
this.inputValue = newVal;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateValue($event) {
|
||||||
|
switch (this.type) {
|
||||||
|
case 'text':
|
||||||
|
this.$emit('input', $event.target.value);
|
||||||
|
break;
|
||||||
|
case 'number':
|
||||||
|
const newValue = this.formatDecimalValue($event.target.value);
|
||||||
|
this.$emit('input', parseFloat(newValue));
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
formatDecimalValue(value) {
|
||||||
|
let decimalValue = value.replace(/[^-0-9.]/g, '');
|
||||||
|
if (this.decimals === 0) {
|
||||||
|
return decimalValue.split('.')[0];
|
||||||
|
}
|
||||||
|
return decimalValue.match(new RegExp(`^-?\\d*(\\.\\d{0,${this.decimals}})?`))[0];
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -8,7 +8,8 @@
|
||||||
'sn-select--blank': !valueLabel,
|
'sn-select--blank': !valueLabel,
|
||||||
'disabled cursor-default': disabled,
|
'disabled cursor-default': disabled,
|
||||||
'cursor-pointer': !withEditCursor,
|
'cursor-pointer': !withEditCursor,
|
||||||
'sci-cursor-edit hover:border-sn-sleepy-grey': !disabled && !isOpen && withEditCursor
|
'sci-cursor-edit hover:border-sn-sleepy-grey': !disabled && !isOpen && withEditCursor,
|
||||||
|
[className]: true
|
||||||
}">
|
}">
|
||||||
<slot>
|
<slot>
|
||||||
<button ref="focusElement" class="sn-select__value">
|
<button ref="focusElement" class="sn-select__value">
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
initialValue: { type: [String, Number] },
|
initialValue: { type: [String, Number] },
|
||||||
placeholder: { type: String },
|
placeholder: { type: String },
|
||||||
noOptionsPlaceholder: { type: String },
|
noOptionsPlaceholder: { type: String },
|
||||||
|
className: { type: String, default: '' },
|
||||||
disabled: { type: Boolean, default: false }
|
disabled: { type: Boolean, default: false }
|
||||||
},
|
},
|
||||||
directives: {
|
directives: {
|
||||||
|
|
|
@ -3,27 +3,37 @@
|
||||||
module RepositoryDatatable
|
module RepositoryDatatable
|
||||||
class RepositoryStockValueSerializer < RepositoryBaseValueSerializer
|
class RepositoryStockValueSerializer < RepositoryBaseValueSerializer
|
||||||
include Canaid::Helpers::PermissionsHelper
|
include Canaid::Helpers::PermissionsHelper
|
||||||
|
include Rails.application.routes.url_helpers
|
||||||
|
|
||||||
def value
|
def value
|
||||||
data = {
|
data = {
|
||||||
stock_formatted: value_object.formatted,
|
stock_formatted: value_object.formatted,
|
||||||
stock_amount: value_object.data,
|
stock_amount: value_object.data,
|
||||||
low_stock_threshold: value_object.low_stock_threshold
|
low_stock_threshold: value_object.low_stock_threshold,
|
||||||
|
stock_url: edit_repository_stock_repository_repository_row_url(scope[:repository],
|
||||||
|
value_object.repository_row)
|
||||||
}
|
}
|
||||||
|
data.merge(reminder_values)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def reminder_values
|
||||||
|
data = {}
|
||||||
if scope.dig(:options, :reminders_enabled) &&
|
if scope.dig(:options, :reminders_enabled) &&
|
||||||
!scope[:repository].is_a?(RepositorySnapshot) &&
|
!scope[:repository].is_a?(RepositorySnapshot) &&
|
||||||
value_object.data.present? &&
|
value_object.data.present? &&
|
||||||
value_object.low_stock_threshold.present?
|
value_object.low_stock_threshold.present?
|
||||||
data[:reminder] = value_object.low_stock_threshold > value_object.data
|
data[:reminder] = value_object.low_stock_threshold > value_object.data
|
||||||
if data[:reminder] && (data[:stock_amount]).positive?
|
if data[:reminder] && value_object.data&.positive?
|
||||||
data[:reminder_text] =
|
data[:reminder_text] =
|
||||||
I18n.t('repositories.item_card.reminders.stock_low', stock_formated: data[:stock_formatted])
|
I18n.t('repositories.item_card.reminders.stock_low', stock_formated: value_object.formatted)
|
||||||
elsif data[:reminder]
|
elsif data[:reminder]
|
||||||
data[:reminder_text] = I18n.t('repositories.item_card.reminders.stock_empty')
|
data[:reminder_text] = I18n.t('repositories.item_card.reminders.stock_empty')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if data[:stock_amount].zero?
|
if value_object.data && value_object.data <= 0
|
||||||
data[:reminder] = true
|
data[:reminder] = true
|
||||||
data[:reminder_text] = I18n.t('repositories.item_card.reminders.stock_empty')
|
data[:reminder_text] = I18n.t('repositories.item_card.reminders.stock_empty')
|
||||||
end
|
end
|
||||||
|
|
|
@ -152,8 +152,13 @@
|
||||||
<!-- Delete file modal -->
|
<!-- Delete file modal -->
|
||||||
<%= render partial: 'assets/asset_delete_modal' %>
|
<%= render partial: 'assets/asset_delete_modal' %>
|
||||||
|
|
||||||
|
<!-- Manage Stock Modal -->
|
||||||
|
<%= render partial: 'shared/manage_stock_value_modal' %>
|
||||||
|
|
||||||
|
<!-- Consume Stock Modal -->
|
||||||
<%= render partial: 'my_modules/repositories/consume_stock_modal'%>
|
<%= render partial: 'my_modules/repositories/consume_stock_modal'%>
|
||||||
|
|
||||||
|
<%= javascript_include_tag 'inputmask' %>
|
||||||
<%= stylesheet_link_tag 'datatables' %>
|
<%= stylesheet_link_tag 'datatables' %>
|
||||||
<%= javascript_include_tag "handsontable.full" %>
|
<%= javascript_include_tag "handsontable.full" %>
|
||||||
<%= render partial: "shared/formulas_libraries" %>
|
<%= render partial: "shared/formulas_libraries" %>
|
||||||
|
|
|
@ -73,12 +73,12 @@
|
||||||
locals: { repository: @repository } %>
|
locals: { repository: @repository } %>
|
||||||
|
|
||||||
<%= render partial: 'repository_columns/manage_column_modal', locals: { my_module_page: false } %>
|
<%= render partial: 'repository_columns/manage_column_modal', locals: { my_module_page: false } %>
|
||||||
<%= render partial: "repository_stock_values/manage_modal" %>
|
|
||||||
<%= render partial: "toolbar_buttons" %>
|
<%= render partial: "toolbar_buttons" %>
|
||||||
<%= render partial: "assign_items_to_task_modal" %>
|
<%= render partial: "assign_items_to_task_modal" %>
|
||||||
|
|
||||||
<%= render partial: 'repository_filters' %>
|
<%= render partial: 'repository_filters' %>
|
||||||
<%= render partial: 'save_repository_filter_modal' %>
|
<%= render partial: 'save_repository_filter_modal' %>
|
||||||
|
<%= render partial: 'shared/manage_stock_value_modal' %>
|
||||||
|
|
||||||
|
|
||||||
<%= javascript_include_tag 'vue_components_action_toolbar' %>
|
<%= javascript_include_tag 'vue_components_action_toolbar' %>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
json.id @repository_row.id
|
||||||
json.repository do
|
json.repository do
|
||||||
json.id @repository.id
|
json.id @repository.id
|
||||||
json.name @repository.name
|
json.name @repository.name
|
||||||
|
@ -20,6 +21,13 @@ json.actions do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
json.direct_file_upload_path rails_direct_uploads_url
|
json.direct_file_upload_path rails_direct_uploads_url
|
||||||
|
json.stock do
|
||||||
|
if @repository_row.has_stock?
|
||||||
|
json.stock_value_url edit_repository_stock_repository_repository_row_url(@repository, @repository_row)
|
||||||
|
elsif @repository.has_stock_management?
|
||||||
|
json.stock_value_url new_repository_stock_repository_repository_row_url(@repository, @repository_row)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
json.default_columns do
|
json.default_columns do
|
||||||
|
@ -58,8 +66,10 @@ json.custom_columns do
|
||||||
end
|
end
|
||||||
|
|
||||||
if repository_cell
|
if repository_cell
|
||||||
json.merge! **serialize_repository_cell_value(repository_cell, @repository.team, @repository, reminders_enabled: @reminders_present).merge(
|
json.merge! serialize_repository_cell_value(
|
||||||
**repository_cell.repository_column.as_json(only: %i(id name data_type))
|
repository_cell, @repository.team, @repository, reminders_enabled: @reminders_present
|
||||||
|
).merge(
|
||||||
|
repository_cell.repository_column.as_json(only: %i(id name data_type))
|
||||||
).merge(options)
|
).merge(options)
|
||||||
else
|
else
|
||||||
json.merge! repository_column.as_json(only: %i(id name data_type)).merge(options)
|
json.merge! repository_column.as_json(only: %i(id name data_type)).merge(options)
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<div class="modal repository-stock-modal"
|
|
||||||
id="manage-repository-stock-value-modal"
|
|
||||||
tabindex="-1"
|
|
||||||
role="dialog"
|
|
||||||
aria-labelledby="manageRepositoryStockValueLabel">
|
|
||||||
<div class="modal-dialog" role="document">
|
|
||||||
<div class="modal-content">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<%= javascript_include_tag 'repositories/stock' %>
|
|
|
@ -1,143 +0,0 @@
|
||||||
<%= form_tag update_repository_stock_repository_repository_row_path(@repository, @repository_row), method: :post, remote: true, novalidate: true do %>
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="<%= t('general.close') %>">
|
|
||||||
<i class="sn-icon sn-icon-close"></i>
|
|
||||||
</button>
|
|
||||||
<h4 class="modal-title" id="modal-delete-module-label">
|
|
||||||
<% if repository_stock_value.new_record? %>
|
|
||||||
<%= t('repository_stock_values.manage_modal.title', item: repository_row.name) %>
|
|
||||||
<% else %>
|
|
||||||
<%= t('repository_stock_values.manage_modal.edit_title', item: repository_row.name) %>
|
|
||||||
<% end %>
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<%= hidden_field_tag 'repository_stock_value[amount]', repository_stock_value.amount %>
|
|
||||||
<%= hidden_field_tag 'initial_units', repository_stock_value.repository_stock_unit_item_id %>
|
|
||||||
<%= hidden_field_tag 'change_amount' %>
|
|
||||||
<%= hidden_field_tag 'operator', 'set' %>
|
|
||||||
<p><%= t('repository_stock_values.manage_modal.enter_amount') %></p>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-5 !pr-0">
|
|
||||||
<label><%= t('repository_stock_values.manage_modal.operation') %></label>
|
|
||||||
<% if repository_stock_value.id %>
|
|
||||||
<div class="btn-group" role="group" aria-label="Operator group">
|
|
||||||
<button type="button" data-operator="set" class="btn btn-primary stock-operator-option"><%= t('repository_stock_values.manage_modal.set') %></button>
|
|
||||||
<button type="button" data-operator="add" class="btn btn-secondary stock-operator-option"><%= t('repository_stock_values.manage_modal.add') %></button>
|
|
||||||
<button type="button" data-operator="remove" class="btn btn-secondary stock-operator-option"><%= t('repository_stock_values.manage_modal.remove') %></button>
|
|
||||||
</div>
|
|
||||||
<% else %>
|
|
||||||
<div class="btn-group" role="group" aria-label="Operator group">
|
|
||||||
<button type="button" data-operator="set" class="btn btn-primary"><%= t('repository_stock_values.manage_modal.set') %></button>
|
|
||||||
<button type="button" data-operator="add" class="btn btn-secondary disabled"><%= t('repository_stock_values.manage_modal.add') %></button>
|
|
||||||
<button type="button" data-operator="remove" class="btn btn-secondary disabled"><%= t('repository_stock_values.manage_modal.remove') %></button>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-7">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<div class="sci-input-container" data-error-text="<%= t('repository_stock_values.manage_modal.amount_error') %>">
|
|
||||||
<label><%= t('repository_stock_values.manage_modal.amount') %></label>
|
|
||||||
<input id="stock-input-amount"
|
|
||||||
class="sci-input-field"
|
|
||||||
type="text"
|
|
||||||
autocomplete="off"
|
|
||||||
name="input-amount"
|
|
||||||
data-operator="set"
|
|
||||||
tabindex="1"
|
|
||||||
data-current-amount="<%= repository_stock_value.amount %>"
|
|
||||||
data-decimals="<%= repository_stock_column.metadata['decimals'] %>"
|
|
||||||
value="<%= repository_stock_value.formatted_value %>"
|
|
||||||
placeholder="<%= t("repository_stock_values.manage_modal.amount_placeholder_new") %>"
|
|
||||||
required />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<label><%= t('repository_stock_values.manage_modal.unit') %></label>
|
|
||||||
<select class="form-control" name="repository_stock_value[unit_item_id]" id="repository-stock-value-units" required>
|
|
||||||
<option valus=""><%= t('repository_stock_values.manage_modal.unit_prompt') %></option>
|
|
||||||
<% unit_items.each do |unit_item| %>
|
|
||||||
<option value="<%= unit_item.id %>" <%= 'selected' if repository_stock_value.repository_stock_unit_item == unit_item || unit_items.one?%>>
|
|
||||||
<%= unit_item.data %>
|
|
||||||
</option>
|
|
||||||
<% end %>
|
|
||||||
</select>
|
|
||||||
<div class="input-error-message">
|
|
||||||
<%= t('repository_stock_values.manage_modal.unit_error') %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<div class="stock-comment-field sci-input-container" data-error-text="<%= t('repository_stock_values.manage_modal.comment_limit') %>">
|
|
||||||
<label><%= t('repository_stock_values.manage_modal.comment') %></label>
|
|
||||||
<input class="sci-input-field"
|
|
||||||
type="text"
|
|
||||||
tabindex="3"
|
|
||||||
name="repository_stock_value[comment]"
|
|
||||||
id="repository-stock-value-comment"
|
|
||||||
placeholder="<%= t('repository_stock_values.manage_modal.comment_placeholder') %>">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<div class="repository-stock-reminder-selector">
|
|
||||||
<div class="sci-checkbox-container">
|
|
||||||
<input type="checkbox" name="reminder-enabled" tabindex="4" class="sci-checkbox" id="reminder-selector-checkbox" <%= "checked" if repository_stock_value.low_stock_threshold.present? %>/>
|
|
||||||
<span class="sci-checkbox-label"></span>
|
|
||||||
</div>
|
|
||||||
<%= t('repository_stock_values.manage_modal.create_reminder') %>
|
|
||||||
</div>
|
|
||||||
<div class="repository-stock-reminder-value <%= "hidden" if repository_stock_value.low_stock_threshold.blank? %>">
|
|
||||||
<span><%= t('repository_stock_values.manage_modal.reminder_at') %></span>
|
|
||||||
<div class="sci-input-container" data-error-text="<%= t('repository_stock_values.manage_modal.enter_ammount') %>">
|
|
||||||
<input type="text"
|
|
||||||
autocomplete="off"
|
|
||||||
id="low_stock_threshold"
|
|
||||||
name="repository_stock_value[low_stock_threshold]"
|
|
||||||
value="<%= repository_stock_value.formatted_treshold %>"
|
|
||||||
data-decimals="<%= repository_stock_column.metadata['decimals'] %>"
|
|
||||||
class="sci-input-field"
|
|
||||||
tabindex="5"
|
|
||||||
placeholder="Enter amount"/>
|
|
||||||
</div>
|
|
||||||
<span class="units">
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% unless repository_stock_value.new_record? %>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<div class="stock-update-view">
|
|
||||||
<div class="stock-initial-container <%= 'negative' if repository_stock_value.amount.negative? %>">
|
|
||||||
<span class="subtitle"><%= t('repository_stock_values.manage_modal.current_stock') %></span>
|
|
||||||
<span class="value"><%= repository_stock_value.formatted_value %></span>
|
|
||||||
<span class="units"><%= repository_stock_value.repository_stock_unit_item&.data %></span>
|
|
||||||
</div>
|
|
||||||
<div class="stock-arrow">
|
|
||||||
<i class="sn-icon sn-icon-arrow-right"></i>
|
|
||||||
</div>
|
|
||||||
<div class="stock-final-container <%= 'negative' if repository_stock_value.amount.negative? %> ">
|
|
||||||
<span class="subtitle"><%= t('repository_stock_values.manage_modal.new_stock') %></span>
|
|
||||||
<span class="value"><%= repository_stock_value.formatted_value %></span>
|
|
||||||
<span class="units"><%= repository_stock_value.repository_stock_unit_item&.data %></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button"
|
|
||||||
id="cancel"
|
|
||||||
class="btn btn-secondary"
|
|
||||||
tabindex="7"
|
|
||||||
data-dismiss="modal"><%=t 'general.cancel' %></button>
|
|
||||||
<%= submit_tag t('repository_stock_values.manage_modal.save_stock'), class: "btn btn-primary update-repository-stock", tabindex: "6" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
13
app/views/repository_stock_values/edit.json.jbuilder
Normal file
13
app/views/repository_stock_values/edit.json.jbuilder
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
json.stock_url update_repository_stock_repository_repository_row_url(@repository, @repository_row)
|
||||||
|
json.repository_row_name @repository_row.name
|
||||||
|
json.stock_value do
|
||||||
|
json.id @repository_stock_value.id
|
||||||
|
json.amount @repository_stock_value.formatted_value
|
||||||
|
json.decimals @repository_column.metadata['decimals']
|
||||||
|
json.units @repository_column.repository_stock_unit_items.pluck(:id, :data)
|
||||||
|
json.unit @repository_stock_value.repository_stock_unit_item_id
|
||||||
|
json.reminder_enabled @repository_stock_value.low_stock_threshold.present?
|
||||||
|
json.low_stock_treshold @repository_stock_value.formatted_treshold
|
||||||
|
end
|
8
app/views/repository_stock_values/new.json.jbuilder
Normal file
8
app/views/repository_stock_values/new.json.jbuilder
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
json.stock_url update_repository_stock_repository_repository_row_url(@repository, @repository_row)
|
||||||
|
json.repository_row_name @repository_row.name
|
||||||
|
json.stock_value do
|
||||||
|
json.decimals @repository_column.metadata['decimals']
|
||||||
|
json.units @repository_column.repository_stock_unit_items.pluck(:id, :data)
|
||||||
|
end
|
5
app/views/shared/_manage_stock_value_modal.erb
Normal file
5
app/views/shared/_manage_stock_value_modal.erb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<div id="manageStockValueModal" data-behaviour="vue">
|
||||||
|
<manage-stock-value-modal />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= javascript_include_tag('vue_components_manage_stock_value_modal') %>
|
|
@ -81,7 +81,6 @@ Rails.application.config.assets.precompile += %w(label_printers/zebra_settings.j
|
||||||
Rails.application.config.assets.precompile += %w(repositories/index.js)
|
Rails.application.config.assets.precompile += %w(repositories/index.js)
|
||||||
Rails.application.config.assets.precompile += %w(repositories/share_modal.js)
|
Rails.application.config.assets.precompile += %w(repositories/share_modal.js)
|
||||||
Rails.application.config.assets.precompile += %w(repositories/edit.js)
|
Rails.application.config.assets.precompile += %w(repositories/edit.js)
|
||||||
Rails.application.config.assets.precompile += %w(repositories/stock.js)
|
|
||||||
Rails.application.config.assets.precompile += %w(repositories/repository_datatable.js)
|
Rails.application.config.assets.precompile += %w(repositories/repository_datatable.js)
|
||||||
Rails.application.config.assets.precompile += %w(global_activities/index.js)
|
Rails.application.config.assets.precompile += %w(global_activities/index.js)
|
||||||
Rails.application.config.assets.precompile += %w(repositories/show.js)
|
Rails.application.config.assets.precompile += %w(repositories/show.js)
|
||||||
|
|
|
@ -2294,6 +2294,10 @@ en:
|
||||||
expand: 'Expand'
|
expand: 'Expand'
|
||||||
collapse: 'Collapse'
|
collapse: 'Collapse'
|
||||||
dropdown_placeholder: 'Select'
|
dropdown_placeholder: 'Select'
|
||||||
|
date_time:
|
||||||
|
errors:
|
||||||
|
set_all_or_none: 'Needs to set both or none'
|
||||||
|
not_valid_range: 'Range is not valid.'
|
||||||
highlight_component:
|
highlight_component:
|
||||||
information_label: 'Information'
|
information_label: 'Information'
|
||||||
custom_columns_label: 'Custom columns'
|
custom_columns_label: 'Custom columns'
|
||||||
|
|
|
@ -43,7 +43,8 @@ const entryList = {
|
||||||
vue_components_open_vector_editor: './app/javascript/packs/vue/open_vector_editor.js',
|
vue_components_open_vector_editor: './app/javascript/packs/vue/open_vector_editor.js',
|
||||||
vue_navigation_breadcrumbs: './app/javascript/packs/vue/navigation/breadcrumbs.js',
|
vue_navigation_breadcrumbs: './app/javascript/packs/vue/navigation/breadcrumbs.js',
|
||||||
vue_protocol_file_import_modal: './app/javascript/packs/vue/protocol_file_import_modal.js',
|
vue_protocol_file_import_modal: './app/javascript/packs/vue/protocol_file_import_modal.js',
|
||||||
vue_components_export_stock_consumption_modal: './app/javascript/packs/vue/export_stock_consumption_modal.js'
|
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'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Engine pack loading based on https://github.com/rails/webpacker/issues/348#issuecomment-635480949
|
// Engine pack loading based on https://github.com/rails/webpacker/issues/348#issuecomment-635480949
|
||||||
|
|
Loading…
Reference in a new issue