Merge branch 'features/label-templates' into ai-sci-7054-add-flyout-to-search-repository-columns-to-zpl-editor

This commit is contained in:
aignatov-bio 2022-08-24 17:48:48 +02:00 committed by GitHub
commit 6d8908c1f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 257 additions and 8 deletions

View file

@ -89,6 +89,7 @@ gem 'underscore-rails'
gem 'wicked_pdf'
gem 'wkhtmltopdf-heroku', '2.12.5'
gem 'aws-sdk-lambda'
gem 'aws-sdk-rails'
gem 'aws-sdk-s3'
gem 'delayed_job_active_record'

View file

@ -137,6 +137,9 @@ GEM
aws-sdk-kms (1.41.0)
aws-sdk-core (~> 3, >= 3.109.0)
aws-sigv4 (~> 1.1)
aws-sdk-lambda (1.57.0)
aws-sdk-core (~> 3, >= 3.109.0)
aws-sigv4 (~> 1.1)
aws-sdk-rails (3.6.0)
aws-record (~> 2)
aws-sdk-ses (~> 1)
@ -634,6 +637,7 @@ DEPENDENCIES
auto_strip_attributes (~> 2.1)
autosize-rails
awesome_print
aws-sdk-lambda
aws-sdk-rails
aws-sdk-s3
base62

View file

@ -0,0 +1,57 @@
.label-preview {
margin-top: 16px;
max-width: 410px;
}
.label-preview__header {
align-items: center;
display: flex;
justify-content: space-between;
}
.label-preview__options-button {
color: $brand-primary-light;
cursor: pointer;
}
.label-preview__image {
border-radius: 4px;
box-shadow: 0 0 8px 0 rgba(0, 0, 0, .2);
margin-top: 16px;
img {
max-width: 100%;
}
}
.label-preview__controls {
height: 0;
overflow: hidden;
&.open {
height: auto;
margin-top: 16px;
}
}
.label-preview__controls__size {
display: flex;
margin-top: 16px;
.sci-input-container {
margin-right: 8px;
&:last-child {
flex-basis: 50%;
flex-shrink: 0;
margin-right: 0;
}
}
}
.label-preview__refresh {
cursor: pointer;
margin: 16px auto;
max-width: 160px;
text-align: center;
}

View file

@ -4,7 +4,7 @@ class LabelTemplatesController < ApplicationController
include InputSanitizeHelper
before_action :check_feature_enabled
before_action :check_view_permissions, only: %i(index datatable)
before_action :check_view_permissions, except: %i(create duplicate set_default delete update)
before_action :check_manage_permissions, only: %i(create duplicate set_default delete update)
before_action :load_label_templates, only: %i(index datatable)
before_action :load_label_template, only: %i(show set_default update)
@ -89,6 +89,17 @@ class LabelTemplatesController < ApplicationController
render json: LabelTemplates::TagService.new(current_team).tags
end
def zpl_preview
service = LabelTemplatesPreviewService.new(params, current_user)
payload = service.generate_zpl_preview!
if service.error.blank?
render json: { base64_preview: payload }
else
render json: { error: I18n.t('errors.general') }, status: :unprocessable_entity
end
end
private
def check_feature_enabled

View file

@ -16,6 +16,7 @@ window.initLabelTemplateComponent = () => {
return {
labelTemplateUrl: $('#labelTemplateContainer').data('label-template-url'),
labelTemplatesUrl: $('#labelTemplateContainer').data('label-templates-url'),
previewUrl: $('#labelTemplateContainer').data('preview-url'),
newLabel: $('#labelTemplateContainer').data('new-label')
};
}

View file

@ -0,0 +1,128 @@
<template>
<div ref="labelPreview" class="label-preview">
<div class="label-preview__header">
<div class="title">
{{ i18n.t('label_templates.show.preview_title') }}
</div>
<div class="label-preview__options-button" @click="optionsOpen = !optionsOpen">
{{ i18n.t('label_templates.label_preview.options') }}
<i class="fas" :class="{ 'fa-angle-down': !optionsOpen, 'fa-angle-up': optionsOpen }"></i>
</div>
</div>
<div class="label-preview__controls" :class="{'open': optionsOpen}">
<div class="label-preview__controls__units">
<div class="sci-input-container">
<label>{{ i18n.t('label_templates.label_preview.units') }}</label>
<DropdownSelector
:disableSearch="true"
:options="[{ value: 'in', label: i18n.t(`label_templates.label_preview.in`) }, { value: 'mm', label: i18n.t(`label_templates.label_preview.mm`) }]"
:selectorId="'UnitSelector'"
:selectedValue="unit"
@dropdown:changed="updateUnit" />
</div>
</div>
<div class="label-preview__controls__size">
<div class="sci-input-container">
<label>{{ i18n.t('label_templates.label_preview.height') }}</label>
<input v-model="height" type="text" class="sci-input-field" />
</div>
<div class="sci-input-container">
<label>{{ i18n.t('label_templates.label_preview.width') }}</label>
<input v-model="width" type="text" class="sci-input-field" />
</div>
<div class="sci-input-container">
<label>{{ i18n.t('label_templates.label_preview.density') }}</label>
<DropdownSelector
:key="unit"
:disableSearch="true"
:options="unit === 'in' ? DPI_RESOLUTION_OPTIONS : DPMM_RESOLUTION_OPTIONS"
:selectorId="'DensitySelector'"
:selectedValue="density"
@dropdown:changed="updateDensity" />
</div>
</div>
<div class="label-preview__refresh" @click="refreshPreview">
<i class="fas fa-sync"></i>
{{ i18n.t('label_templates.label_preview.refresh_preview') }}
</div>
</div>
<div v-if="base64Image" class="label-preview__image">
<img :src="`data:image/png;base64,${base64Image}`" />
</div>
</div>
</template>
<script>
const DPI_RESOLUTION_OPTIONS = [
{ value: 6, label: '6 dpi' },
{ value: 8, label: '8 dpi', selected: true },
{ value: 12, label: '12 dpi'},
{ value: 24, label: '24 dpi' }
]
const DPMM_RESOLUTION_OPTIONS = [
{ value: 6, label: '152 dpmm (6 dpi)' },
{ value: 8, label: '203 dpmm (8 dpi)', selected: true },
{ value: 12, label: '300 dpmm (12 dpi)' },
{ value: 24, label: '600 dpmm (24 dpi)' }
]
import DropdownSelector from 'vue/shared/dropdown_selector.vue'
export default {
name: 'LabelPreview',
components: { DropdownSelector },
props: {
zpl: { type: String, required: true },
previewUrl: { type: String, required: true }
},
data() {
return {
DPMM_RESOLUTION_OPTIONS,
DPI_RESOLUTION_OPTIONS,
optionsOpen: false,
width: null,
height: null,
unit: 'in',
density: 8,
base64Image: null,
imageStyle: ''
}
},
mounted() {
this.refreshPreview();
},
computed: {
widthMm() {
return this.unit === 'in' ? this.width * 25.4 : this.width;
},
heightMm() {
return this.unit === 'in' ? this.height * 25.4 : this.height;
}
},
methods: {
refreshPreview() {
$.ajax({
url: this.previewUrl,
type: 'GET',
data: {
zpl: this.zpl,
width: this.widthMm,
height: this.heightMm,
density: this.density
},
success: (result) => {
this.base64Image = result.base64_preview;
}
});
},
updateUnit(unit) {
this.unit = unit;
},
updateDensity(density) {
this.density = density;
}
}
}
</script>

View file

@ -81,9 +81,7 @@
</div>
<div class="label-preview-container">
<div class="title">
{{ i18n.t('label_templates.show.preview_title') }}
</div>
<LabelPreview :zpl='labelTemplate.attributes.content' :previewUrl="previewUrl" />
</div>
</div>
</div>
@ -94,12 +92,14 @@
import InlineEdit from 'vue/shared/inline_edit.vue'
import InsertFieldDropdown from 'vue/label_template/insert_field_dropdown.vue'
import LabelPreview from './components/label_preview.vue'
export default {
name: 'LabelTemplateContainer',
props: {
labelTemplateUrl: String,
labelTemplatesUrl: String,
previewUrl: String,
newLabel: Boolean
},
data() {
@ -114,7 +114,7 @@
cursorPos: 0
}
},
components: {InlineEdit, InsertFieldDropdown},
components: {InlineEdit, InsertFieldDropdown, LabelPreview},
created() {
$.get(this.labelTemplateUrl, (result) => {
this.labelTemplate = result.data

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
class LabelTemplatesPreviewService
extend Service
attr_reader :error, :preview
def initialize(params, user)
@user = user
@params = params
end
def generate_zpl_preview!
client = Aws::Lambda::Client.new(region: ENV['AWS_REGION'])
resp = client.invoke(
function_name: 'BinaryKitsZplViewer',
invocation_type: 'RequestResponse',
log_type: 'Tail',
payload:
"{ \"content\": #{@params[:zpl].to_json},"\
"\"width\": #{@params[:width]},"\
"\"height\": #{@params[:height]},"\
"\"density\": #{@params[:density]} "\
"}"
)
if resp.function_error.nil?
@preview = resp.payload.string.delete('"')
else
@error = resp.function_error.string
end
end
end

View file

@ -6,12 +6,14 @@
<div id="labelTemplateContainer"
data-label-template-url="<%= label_template_path(params[:id], format: :json) %>"
data-label-templates-url="<%= label_templates_path() %>"
data-label-templates-url="<%= label_templates_path %>"
data-preview-url="<%= zpl_preview_label_templates_path %>"
data-new-label="<%= params[:new_label] || false %>"
>
<label-template-container
:label-template-url="labelTemplateUrl"
:label-templates-url="labelTemplatesUrl"
:preview-url="previewUrl"
:new-label="newLabel"
/>
</div>

View file

@ -872,7 +872,16 @@ en:
name: 'Name'
added_on: 'Added On'
added_by: 'Added by'
label_preview:
title: 'Preview'
options: 'Options'
units: 'Measurement units'
height: 'Height'
width: 'Width'
density: 'Density'
refresh_preview: 'Refresh preview'
mm: 'Millimeters (mm) 1 cm = 10 mm'
in: 'Inches (in)'
promo:
head_title: 'Label templates'
promo_title: 'Label all your tubes & containers by your own standards'

View file

@ -54,6 +54,7 @@ Rails.application.routes.draw do
post :delete
get :datatable
get :template_tags
get :zpl_preview
end
end

View file

@ -17,11 +17,13 @@ class AddColumnsToLabelTemplates < ActiveRecord::Migration[6.1]
add_reference :label_templates, :team, index: true, foreign_key: true
if Team.count.positive?
LabelTemplate.first.update(
# rubocop:disable Rails/SkipsModelValidations
LabelTemplate.first.update_columns(
created_by_id: Team.first.created_by_id,
last_modified_by_id: Team.first.created_by_id,
team_id: Team.first.id
)
# rubocop:enable Rails/SkipsModelValidations
end
end