mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-04 02:45:53 +08:00
Add Label template list screen - view mode [SCI-7018] (#4292)
* Initial label template datatable [SCI-7018] * Add new columns to LabelTemplate and update datatable view [SCI-7018] * Fix after rebase [SCI-7018] * Fix migration, disable checkboxes in view mode and fix label template to team level [SCI-7018]
This commit is contained in:
parent
118ae55f2f
commit
ad4f52d912
13 changed files with 400 additions and 4 deletions
4
app/assets/images/label_template_icons/zpl.svg
Normal file
4
app/assets/images/label_template_icons/zpl.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.2315 4.00001L13.9001 8.00001L11.2312 12H1V12H0V12C0 12.2652 0.105357 12.5196 0.292893 12.7071C0.48043 12.8947 0.734784 13 1 13H11.2312C11.3957 13.0006 11.5577 12.9604 11.7028 12.8829C11.8479 12.8055 11.9715 12.6932 12.0625 12.5563L14.9187 8.27501C14.9741 8.19398 15.0037 8.09814 15.0037 8.00001C15.0037 7.90188 14.9741 7.80603 14.9187 7.72501L12.0625 3.44376C11.9715 3.30678 11.8479 3.19454 11.7028 3.11709C11.5577 3.03965 11.3957 2.99941 11.2312 3.00001H1C0.734784 3.00001 0.48043 3.10536 0.292893 3.2929C0.105358 3.48043 1.7995e-06 3.73479 0 4H1V4.00001L11.2315 4.00001Z" fill="#A0A0A8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.35297e-06 5.5C2.35297e-06 5.22386 0.22386 5 0.500002 5H2.5C2.66591 5 2.82102 5.0823 2.91404 5.21969C3.00705 5.35707 3.02586 5.53165 2.96424 5.6857L1.23852 10H2.5C2.77614 10 3 10.2239 3 10.5C3 10.7761 2.77614 11 2.5 11H0.500002C0.33409 11 0.178984 10.9177 0.0859687 10.7803C-0.00704625 10.6429 -0.0258541 10.4683 0.035764 10.3143L1.76149 6H0.500002C0.22386 6 2.35297e-06 5.77614 2.35297e-06 5.5ZM10.5 11C10.775 11 11 10.775 11 10.5C11 10.225 10.775 10 10.5 10H9V5.5C9 5.225 8.775 5 8.5 5C8.225 5 8 5.225 8 5.5V10.5C8 10.775 8.225 11 8.5 11H10.5ZM7 7C7 6.03437 6.21563 5 5.25 5H4.5C4.22375 5 4 5.225 4 5.5V10.5C4 10.775 4.22375 11 4.5 11C4.77625 11 5 10.775 5 10.5V9H5.25C6.21563 9 7 7.96563 7 7ZM5.25 6C5.66563 6 6 6.58438 6 7C6 7.41563 5.66563 8 5.25 8H5V6H5.25Z" fill="#404048"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,107 @@
|
|||
/* global I18n DataTableHelpers */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var LABEL_TEMPLATE_TABLE;
|
||||
|
||||
function renderCheckboxHTML(data, type, row) {
|
||||
return `<div class="sci-checkbox-container">
|
||||
<input type="checkbox" class="sci-checkbox" data-action='toggle'
|
||||
data-label-template-id="${data}" ${row.manage_permission ? '' : 'disabled'}>
|
||||
<span class="sci-checkbox-label"></span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderDefaultTemplateHTML(data) {
|
||||
return data ? '<i class="fas fa-thumbtack"></i>' : '';
|
||||
}
|
||||
|
||||
function renderNameHTML(data, type, row) {
|
||||
return `${data.icon_url}<a href='${row.recordInfoUrl}' class='record-info-link'>${data.name}</a>`;
|
||||
}
|
||||
|
||||
function addAttributesToRow(row, data) {
|
||||
$(row).addClass('label-template-row')
|
||||
.attr('data-id', data['0']);
|
||||
}
|
||||
|
||||
function checkboxToggleCallback() {
|
||||
$("[data-action='toggle']").change(function() {
|
||||
if ($(this).is(':checked')) {
|
||||
$(this).closest('.label-template-row').addClass('selected');
|
||||
} else {
|
||||
$(this).closest('.label-template-row').removeClass('selected');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initToggleAllCheckboxes() {
|
||||
$('input[name="select_all"]').change(function() {
|
||||
if ($(this).is(':checked')) {
|
||||
$("[data-action='toggle']").prop('checked', true);
|
||||
$('.label-template-row').addClass('selected');
|
||||
} else {
|
||||
$("[data-action='toggle']").prop('checked', false);
|
||||
$('.label-template-row').removeClass('selected');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function tableDrowCallback() {
|
||||
checkboxToggleCallback();
|
||||
initToggleAllCheckboxes();
|
||||
}
|
||||
|
||||
// INIT
|
||||
|
||||
function initDatatable() {
|
||||
var $table = $('#label-templates-table');
|
||||
LABEL_TEMPLATE_TABLE = $table.DataTable({
|
||||
dom: "Rt<'pagination-row hidden'<'pagination-info'li><'pagination-actions'p>>",
|
||||
order: [[2, 'desc']],
|
||||
sScrollX: '100%',
|
||||
sScrollXInner: '100%',
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: $table.data('source'),
|
||||
pagingType: 'simple_numbers',
|
||||
colReorder: {
|
||||
fixedColumnsLeft: 1000000 // Disable reordering
|
||||
},
|
||||
columnDefs: [{
|
||||
targets: 0,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
className: 'dt-body-center',
|
||||
sWidth: '1%',
|
||||
render: renderCheckboxHTML
|
||||
}, {
|
||||
targets: 1,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
sWidth: '1%',
|
||||
render: renderDefaultTemplateHTML
|
||||
}, {
|
||||
targets: 2,
|
||||
className: 'label-template-name',
|
||||
render: renderNameHTML
|
||||
}],
|
||||
oLanguage: {
|
||||
sSearch: I18n.t('general.filter')
|
||||
},
|
||||
fnDrawCallback: tableDrowCallback,
|
||||
createdRow: addAttributesToRow,
|
||||
fnInitComplete: function() {
|
||||
DataTableHelpers.initLengthAppearance($table.closest('.dataTables_wrapper'));
|
||||
$('.pagination-row').removeClass('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('.label-templates-index').on('keyup', '.label-templates-search', function() {
|
||||
LABEL_TEMPLATE_TABLE.search($(this).val()).draw();
|
||||
});
|
||||
|
||||
initDatatable();
|
||||
}());
|
54
app/assets/stylesheets/label_template_index.scss
Normal file
54
app/assets/stylesheets/label_template_index.scss
Normal file
|
@ -0,0 +1,54 @@
|
|||
// scss-lint:disable SelectorDepth NestingDepth IdSelector SelectorFormat
|
||||
|
||||
.label-templates-index {
|
||||
.search-label-templates-container {
|
||||
float: right;
|
||||
margin-right: 2em;
|
||||
padding-bottom: 16px;
|
||||
width: 200px;
|
||||
|
||||
.fa-search {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar-row.label-templates-toolbar {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.label-templates-datatable {
|
||||
height: calc(100vh - var(--navbar-height) - var(--content-header-size));
|
||||
|
||||
#label-templates-table_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.dataTables_scroll {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
height: calc(100% - var(--datatable-pagination-row));
|
||||
|
||||
.dataTables_scrollHead {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-row {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label-template-name {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.label-template-icon {
|
||||
padding-bottom: 2px;
|
||||
padding-right: 4px;
|
||||
}
|
|
@ -1,15 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class LabelTemplatesController < ApplicationController
|
||||
include InputSanitizeHelper
|
||||
|
||||
before_action :check_view_permissions
|
||||
before_action :load_label_templates, only: %i(index datatable)
|
||||
|
||||
layout 'fluid'
|
||||
|
||||
def index; end
|
||||
|
||||
def datatable
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render json: ::LabelTemplateDatatable.new(
|
||||
view_context,
|
||||
can_manage_label_templates?(current_team),
|
||||
@label_templates
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
render_404
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_view_permissions
|
||||
render_403 unless can_view_label_templates?(current_team)
|
||||
end
|
||||
|
||||
def load_label_templates
|
||||
@label_templates = LabelTemplate.where(team_id: current_team.id)
|
||||
end
|
||||
end
|
||||
|
|
76
app/datatables/label_template_datatable.rb
Normal file
76
app/datatables/label_template_datatable.rb
Normal file
|
@ -0,0 +1,76 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class LabelTemplateDatatable < CustomDatatable
|
||||
include InputSanitizeHelper
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
TABLE_COLUMNS = %w(
|
||||
label_templates.name
|
||||
label_templates.format
|
||||
label_templates.description
|
||||
label_templates.modified_by
|
||||
label_templates.updated_at
|
||||
label_templates.created_by_user
|
||||
label_templates.created_at
|
||||
).freeze
|
||||
|
||||
def initialize(view, can_manage_templates, label_templates)
|
||||
super(view)
|
||||
@manage_template = can_manage_templates
|
||||
@label_templates = label_templates
|
||||
end
|
||||
|
||||
def sortable_columns
|
||||
@sortable_columns ||= TABLE_COLUMNS
|
||||
end
|
||||
|
||||
def searchable_columns
|
||||
@searchable_columns ||= TABLE_COLUMNS
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def data
|
||||
records.map do |record|
|
||||
{
|
||||
'0' => record.id,
|
||||
'1' => record.default,
|
||||
'2' => append_format_icon(sanitize_input(record.name)),
|
||||
'3' => sanitize_input(record.format),
|
||||
'4' => sanitize_input(record.description),
|
||||
'5' => sanitize_input(record.modified_by),
|
||||
'6' => I18n.l(record.updated_at, format: :full),
|
||||
'7' => sanitize_input(record.created_by_user),
|
||||
'8' => I18n.l(record.created_at, format: :full),
|
||||
'recordInfoUrl' => '',
|
||||
'manage_permission' => @manage_template
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def append_format_icon(data)
|
||||
{ icon_url: ActionController::Base.helpers.image_tag('label_template_icons/zpl.svg', class: 'label-template-icon'),
|
||||
name: data }
|
||||
end
|
||||
|
||||
def get_raw_records
|
||||
res = @label_templates.joins(
|
||||
'LEFT OUTER JOIN users AS creators ' \
|
||||
'ON label_templates.created_by_id = creators.id'
|
||||
).joins(
|
||||
'LEFT OUTER JOIN users AS modifiers '\
|
||||
'ON label_templates.last_modified_by_id = modifiers.id'
|
||||
).select('label_templates.* AS label_templates')
|
||||
.select('creators.full_name AS created_by_user')
|
||||
.select('modifiers.full_name AS modified_by')
|
||||
LabelTemplate.from(res, :label_templates)
|
||||
end
|
||||
|
||||
def filter_records(records)
|
||||
records.where_attributes_like(
|
||||
['label_templates.name', 'label_templates.format', 'label_templates.description',
|
||||
'label_templates.modified_by', 'label_templates.created_by_user'],
|
||||
dt_params.dig(:search, :value)
|
||||
)
|
||||
end
|
||||
end
|
|
@ -1,8 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class LabelTemplate < ApplicationRecord
|
||||
include SearchableModel
|
||||
|
||||
enum language_type: { zpl: 0 }
|
||||
validates :name, presence: true
|
||||
validates :name, presence: true, length: { minimum: Constants::NAME_MIN_LENGTH,
|
||||
maximum: Constants::NAME_MAX_LENGTH }
|
||||
validates :size, presence: true
|
||||
validates :content, presence: true
|
||||
|
||||
|
|
|
@ -60,6 +60,10 @@ Canaid::Permissions.register_for(Team) do
|
|||
can :view_label_templates do |user, team|
|
||||
user.is_normal_user_or_admin_of_team?(team)
|
||||
end
|
||||
|
||||
can :manage_label_templates do |user, team|
|
||||
user.is_admin_of_team?(team)
|
||||
end
|
||||
end
|
||||
|
||||
Canaid::Permissions.register_for(ProjectFolder) do
|
||||
|
|
|
@ -1,8 +1,68 @@
|
|||
<% if current_team %>
|
||||
<% provide(:sidebar_title, t('sidebar.templates.sidebar_title')) %>
|
||||
<% provide(:container_class, "no-second-nav-container") %>
|
||||
<%= content_for :sidebar do %>
|
||||
<%= render partial: "/shared/sidebar/templates_sidebar", locals: {active: :label} %>
|
||||
<% end %>
|
||||
<div class="content-pane flexible">
|
||||
|
||||
<% content_for :head do %>
|
||||
<meta name="turbolinks-cache-control" content="no-cache">
|
||||
<% end %>
|
||||
|
||||
<%= stylesheet_link_tag 'datatables' %>
|
||||
|
||||
|
||||
<div class="content-pane flexible label-templates-index">
|
||||
<div class="content-header sticky-header">
|
||||
<div class="title-row">
|
||||
<h1>
|
||||
<%= t('label_templates.index.head_title') %>
|
||||
</h1>
|
||||
</div>
|
||||
<div id="toolbarWrapper" class="toolbar-row label-templates-toolbar">
|
||||
<div class="sci-input-container left-icon search-label-templates-container">
|
||||
<input type="text"
|
||||
class="sci-input-field label-templates-search"
|
||||
placeholder="<%= t("label_templates.index.search_templates") %>">
|
||||
</input>
|
||||
<i class="fas fa-search"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="content-label-templates-index">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="label-templates-datatable">
|
||||
<table id="label-templates-table"
|
||||
class="table"
|
||||
data-source="<%= label_templates_datatable_path(format: :json) %>">
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="select-all">
|
||||
<div class="sci-checkbox-container">
|
||||
<input name="select_all" type="checkbox" class="sci-checkbox"
|
||||
<%= can_manage_label_templates?(current_team) ? '' : 'disabled' %>>
|
||||
<span class="sci-checkbox-label"></span>
|
||||
</div>
|
||||
</th>
|
||||
<th id="label-template-selected"><i class="fas fa-thumbtack"></i></th>
|
||||
<th id="label-template-name"><%= t('label_templates.index.thead_name') %></th>
|
||||
<th id="label-template-format"><%= t('label_templates.index.format') %></th>
|
||||
<th id="label-template-description"><%= t('label_templates.index.description') %></th>
|
||||
<th id="label-template-updated-by"><%= t('label_templates.index.updated_by') %></th>
|
||||
<th id="label-template-updated-at"><%= t('label_templates.index.updated_at') %></th>
|
||||
<th id="label-template-created-by"><%= t('label_templates.index.created_by') %></th>
|
||||
<th id="label-template-created-at"><%= t('label_templates.index.created_at') %></th>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= javascript_include_tag 'label_templates/label_templates_datatable' %>
|
||||
<% end %>
|
||||
|
|
|
@ -91,6 +91,7 @@ Rails.application.config.assets.precompile += %w(sidebar_toggle.js)
|
|||
Rails.application.config.assets.precompile += %w(reports/reports_datatable.js)
|
||||
Rails.application.config.assets.precompile += %w(reports/save_pdf_to_inventory.js)
|
||||
Rails.application.config.assets.precompile += %w(reports/content.js)
|
||||
Rails.application.config.assets.precompile += %w(label_templates/label_templates_datatable.js)
|
||||
|
||||
# Libraries needed for Handsontable formulas
|
||||
Rails.application.config.assets.precompile += %w(jquery.js)
|
||||
|
|
|
@ -809,6 +809,19 @@ en:
|
|||
select_user_role: "Please select a user role."
|
||||
add_user_generic_error: "An error occurred. "
|
||||
can_add_user_to_project: "Can not add user to the project."
|
||||
|
||||
label_templates:
|
||||
index:
|
||||
head_title: 'Label templates'
|
||||
search_templates: 'Filter templates'
|
||||
thead_name: 'Name'
|
||||
format: 'Format'
|
||||
description: 'Description'
|
||||
updated_by: 'Last updated by'
|
||||
updated_at: 'Last updated on'
|
||||
created_by: 'Created by'
|
||||
created_at: 'Created on'
|
||||
|
||||
|
||||
label_printers:
|
||||
create:
|
||||
|
|
|
@ -45,6 +45,9 @@ Rails.application.routes.draw do
|
|||
to: 'users/settings/account/addons#index',
|
||||
as: 'addons'
|
||||
|
||||
resources :label_templates, only: %i(index new)
|
||||
get 'label_templates/datatable', to: 'label_templates#datatable'
|
||||
|
||||
resources :label_printers, except: :show, path: 'users/settings/account/addons/label_printers' do
|
||||
post :create_fluics, on: :collection
|
||||
end
|
||||
|
@ -54,8 +57,6 @@ Rails.application.routes.draw do
|
|||
get :update_progress_modal, on: :member
|
||||
end
|
||||
|
||||
resources :label_templates
|
||||
|
||||
get 'users/settings/account/connected_accounts',
|
||||
to: 'users/settings/account/connected_accounts#index',
|
||||
as: 'connected_accounts'
|
||||
|
|
42
db/migrate/20220726133419_add_columns_to_label_templates.rb
Normal file
42
db/migrate/20220726133419_add_columns_to_label_templates.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddColumnsToLabelTemplates < ActiveRecord::Migration[6.1]
|
||||
def up
|
||||
change_table :label_templates, bulk: true do |t|
|
||||
t.string :description
|
||||
t.string :format, null: false, default: 'ZPL'
|
||||
t.integer :last_modified_by_id
|
||||
t.integer :created_by_id
|
||||
end
|
||||
|
||||
add_foreign_key :label_templates, :users, column: :last_modified_by_id
|
||||
add_foreign_key :label_templates, :users, column: :created_by_id
|
||||
add_index :label_templates, :last_modified_by_id
|
||||
add_index :label_templates, :created_by_id
|
||||
|
||||
add_reference :label_templates, :team, index: true, foreign_key: true
|
||||
|
||||
if Team.count.positive?
|
||||
LabelTemplate.first.update(
|
||||
created_by_id: Team.first.created_by_id,
|
||||
last_modified_by_id: Team.first.created_by_id,
|
||||
team_id: Team.first.id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
remove_reference :label_templates, :team, index: true, foreign_key: true
|
||||
remove_index :label_templates, column: :last_modified_by_id
|
||||
remove_index :label_templates, column: :created_by_id
|
||||
remove_foreign_key :label_templates, :users, column: :last_modified_by_id
|
||||
remove_foreign_key :label_templates, :users, column: :created_by_id
|
||||
|
||||
change_table :label_templates, bulk: true do |t|
|
||||
t.remove :description
|
||||
t.remove :format, null: false, default: 'ZPL'
|
||||
t.remove :last_modified_by_id
|
||||
t.remove :created_by_id
|
||||
end
|
||||
end
|
||||
end
|
|
@ -29,4 +29,12 @@ if User.count.zero?
|
|||
[],
|
||||
Extends::INITIAL_USER_OPTIONS
|
||||
)
|
||||
|
||||
if LabelTemplate.count.positive?
|
||||
LabelTemplate.first.update(
|
||||
created_by_id: Team.first.created_by_id,
|
||||
last_modified_by_id: Team.first.created_by_id,
|
||||
team_id: Team.first.id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue