workarea-product_additional_details 0.0.0 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be13c908ad82859fbb0828351fab50a8dd2c9b224837696c340a17785a2caa74
4
- data.tar.gz: 5c6eb0fb3ac0baaf6da83afbb790437684616038f606a9fd2fae276e19260ec3
3
+ metadata.gz: 4d24293b5ecd598ce1e4f81865b0e2a5939f5bf47a9eac646edcbf6c4566c811
4
+ data.tar.gz: 1205a137f548433a39144e38d687b31fdcd736beaf969b410112f4631b28a05d
5
5
  SHA512:
6
- metadata.gz: a2ad0cf2c1e7ea9ea5af7efd362dcc0d116704a994e19d8b85f77141d53c4c1e3c3c8d8132b2c626ebb7475b33ff1c4664d377590f5bbac77318ed2a5dd2d8c5
7
- data.tar.gz: 2a220464e42c9137035ca1a29feab91f2e4aca932951cc2e0a98641a348f0662a855ac0f6a8958aca63abacd02ebf7a7bd0a9f74f5483235efa8a84a6b11edd5
6
+ metadata.gz: 21774ab5b8904169c5cd6d8647ad0e30ff81f450812f08fd74cc089597eda3db214255a185af211600051fb28b56d7c661ef130083bb5a1dad3f1b441243197d
7
+ data.tar.gz: 822bb52bb0bc63d8abf23065c71aaac1f60e761d6f6207784cd9d112838ed2f1205e019c424846bd88ee760fb33171455f692465e4fd2c29356197e8c07373b5
@@ -0,0 +1,54 @@
1
+ /*------------------------------------*\
2
+ #TABLES
3
+ \*------------------------------------*/
4
+
5
+ $table-border-color: $border-color !default;
6
+
7
+ $table-header-color: $dark-gray !default;
8
+ $table-cell-color: $font-color !default;
9
+
10
+ $table-row-hover-bg-color: $light-gray !default;
11
+
12
+
13
+ /**
14
+ * 1. various types of content will be found wrapped in paragraph tags within
15
+ * tables
16
+ */
17
+ table {
18
+ margin-bottom: $vertical-margin;
19
+ width: 100%;
20
+ border-collapse: collapse;
21
+
22
+ p { /* [1] */
23
+ margin: 0;
24
+ }
25
+
26
+ p + p { /* [1] */
27
+ margin-top: $spacing-unit;
28
+ }
29
+ }
30
+
31
+
32
+ tr {
33
+ tbody &:hover {
34
+ background: $table-row-hover-bg-color;
35
+ }
36
+ }
37
+
38
+ th, td {
39
+ padding: $spacing-unit;
40
+ text-align: left;
41
+ border-bottom: 1px solid $table-border-color;
42
+ vertical-align: baseline;
43
+ .bottom-align & {
44
+ vertical-align: top;
45
+ }
46
+ }
47
+
48
+ th {
49
+ color: $table-header-color;
50
+ }
51
+
52
+ td {
53
+ color: $table-cell-color;
54
+ }
@@ -0,0 +1,33 @@
1
+ module Workarea
2
+ decorate Admin::CatalogProductsController, with: :product_additional_details do
3
+ decorated do
4
+ # Place code to decorate here that would normally go on the class
5
+ # level, e.g.:
6
+ #
7
+ # field :name, type: String
8
+ end
9
+
10
+ class_methods do
11
+ # Place methods to define on the class level here. These methods
12
+ # will be available by calling Admin::CatalogProductsController.your_method. Do
13
+ # not prefix these methods with `self.`
14
+ end
15
+
16
+ def update
17
+ set_additional_details
18
+ super
19
+ end
20
+
21
+ def set_additional_details
22
+ @product.additional_details = HashUpdate.new(
23
+ original: @product.additional_details,
24
+ adds: params[:new_additional_details],
25
+ updates: params[:additional_details],
26
+ removes: params[:additional_details_to_remove]
27
+ ).result_grouped
28
+ end
29
+ # Instance methods can go right in the main definition of the
30
+ # decorator, as it is a module that gets prepended into the class of
31
+ # your choice.
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ module Workarea
2
+ decorate Admin::CatalogVariantsController, with: :product_additional_details do
3
+
4
+ def update
5
+ @variant = @product.variants.find(params[:id])
6
+ set_details
7
+ set_additional_details
8
+
9
+ if @variant.update_attributes(params[:variant])
10
+ flash[:success] = t('workarea.admin.catalog_variants.flash_messages.saved')
11
+ redirect_to catalog_product_variants_path(@product)
12
+ else
13
+ flash[:error] = t('workarea.admin.catalog_variants.flash_messages.changes_error')
14
+ render :edit
15
+ end
16
+ end
17
+
18
+ def set_additional_details
19
+ @variant.additional_details = HashUpdate.new(
20
+ original: @product.additional_details,
21
+ adds: params[:new_additional_details],
22
+ updates: params[:additional_details],
23
+ removes: params[:additional_details_to_remove]
24
+ ).result_grouped
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,10 @@
1
+ module Workarea
2
+ decorate Admin::CreateCatalogProductsController, with: :product_additional_details do
3
+ def save_details
4
+ @product.additional_details = HashUpdate
5
+ .new(original: @product.additional_details, updates: params[:additional_details])
6
+ .result_grouped
7
+ super
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ decorate Catalog::Product, with: :product_additional_details do
3
+ decorated do
4
+ field :additional_details, type: Hash, default: {}, localize: true
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ decorate Catalog::Variant, with: :product_additional_details do
3
+ decorated do
4
+ field :additional_details, type: Hash, default: {}, localize: true
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,93 @@
1
+ module Workarea
2
+ module Search
3
+ class Storefront
4
+ class Product
5
+ module Text
6
+ def catalog_content
7
+ [model.browser_title, model.meta_description, model.description]
8
+ .reject(&:blank?)
9
+ .join(' ')
10
+ end
11
+
12
+ # A list of category names to which this product belongs,
13
+ # allows finding products by category names in search.
14
+ #
15
+ # @return [String]
16
+ #
17
+ def category_names
18
+ categorization.to_models.map(&:name).join(', ')
19
+ end
20
+
21
+ # A textual version of the product's filters hash that
22
+ # will be stored and analyzed in the search index.
23
+ #
24
+ # @return [String]
25
+ #
26
+ def facets_content
27
+ HashText.new(model.filters).text
28
+ end
29
+
30
+ # A textual version of the product's filters hash that
31
+ # will be stored and analyzed in the search index.
32
+ #
33
+ # @return [String]
34
+ #
35
+ def details_content
36
+ "#{HashText.new(model.details).text} #{variant_details_text} #{additional_details_content}"
37
+ end
38
+
39
+ # Text from the product's details hash and it's variants' details
40
+ # hash. Allows finding a product by one of these values.
41
+ #
42
+ # @return [String]
43
+ #
44
+ def details
45
+ "#{HashText.new(model.details).text} #{variant_details_text} #{additional_details_content}"
46
+ end
47
+
48
+ # Text from additional details hash
49
+ def additional_details_content
50
+ if model.additional_details.present? && model.additional_details.any?
51
+ parse_addtional_details(model.additional_details)
52
+ end
53
+ end
54
+
55
+ # Content to put in the index for making search query suggestions.
56
+ # Includes all content for the product.
57
+ #
58
+ # @return [String]
59
+ #
60
+ def suggestion_content
61
+ [
62
+ model.name,
63
+ category_names,
64
+ facets_content,
65
+ details_content
66
+ ].join(' ')
67
+ end
68
+
69
+ def variant_details_text
70
+ @variant_details_text ||= model.variants.active.map do |variant|
71
+ "#{variant.name} #{HashText.new(variant.details).text}"
72
+ end.join(' ')
73
+ end
74
+
75
+ private
76
+ # extract text content from html content
77
+ def parse_addtional_details(details)
78
+ parsed_data = []
79
+ details.each do |key, value|
80
+ data = Nokogiri::HTML.parse(value) if value.is_a?(String)
81
+ if data.present?
82
+ data.traverse do |node|
83
+ parsed_data.push(node.text)
84
+ end
85
+ end
86
+ end
87
+ parsed_data.flatten.compact.uniq.join(" ")
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,43 @@
1
+ module Workarea
2
+ decorate HashUpdate, with: :product_additional_details do
3
+ decorated do
4
+ # Place code to decorate here that would normally go on the class
5
+ # level, e.g.:
6
+ #
7
+ # field :name, type: String
8
+ end
9
+
10
+ class_methods do
11
+ # Place methods to define on the class level here. These methods
12
+ # will be available by calling HashUpdate.your_method. Do
13
+ # not prefix these methods with `self.`
14
+ end
15
+
16
+ def result_grouped
17
+ apply_to_grouped(@original.deep_dup)
18
+ end
19
+
20
+ private
21
+
22
+ def apply_to_grouped(hash)
23
+ @adds.each do |tuple|
24
+ key, value = *tuple
25
+ hash[key] = value
26
+ end
27
+
28
+ @updates.each do |tuple|
29
+ key, value = *tuple
30
+ hash[key] = value
31
+ end
32
+
33
+ @removes.each do |key|
34
+ hash.delete(key)
35
+ end
36
+
37
+ hash.delete_if { |k, v| k.blank? || v.blank? }
38
+ end
39
+ # Instance methods can go right in the main definition of the
40
+ # decorator, as it is a module that gets prepended into the class of
41
+ # your choice.
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ .section.section--additional-details
2
+ %h2= "Additional Details"
3
+
4
+ %table
5
+ %thead
6
+ %tr
7
+ %th= t('workarea.admin.catalog_products.edit.details.name')
8
+ %th= "Content"
9
+ %th.align-center= t('workarea.admin.actions.delete')
10
+ %tbody.bottom-align
11
+ - product.additional_details.each do |name, value|
12
+ %tr
13
+ %td
14
+ .property
15
+ = label_tag "details_#{name}" do
16
+ #{name}
17
+ %td
18
+ .property
19
+ = hidden_field_tag 'additional_details[]', name, id: nil
20
+ = text_area_tag 'additional_details[]', value, class: 'text-box text-box--i18n', id: nil
21
+ %td.align-center= check_box_tag 'additional_details_to_remove[]', name, false, id: nil, title: "#{t('workarea.admin.actions.delete')}: #{name} #{value}"
22
+ %tr{ data: { cloneable_row: '' } }
23
+ %td
24
+ .property
25
+ = text_field_tag 'new_additional_details[]', nil, id: nil, class: 'text-box text-box--i18n', title: t('workarea.admin.catalog_products.edit.details.new_attribute_name'), placeholder: t('workarea.admin.catalog_products.edit.details.new_attribute_name_placeholder')
26
+ %span.property__note= "Example: User Manual"
27
+ %td
28
+ .property
29
+ = text_area_tag 'new_additional_details[]', nil, id: nil, class: 'text-box text-box--i18n', title: t('workarea.admin.catalog_products.edit.details.new_attribute_value'), placeholder: t('workarea.admin.catalog_products.edit.details.new_attribute_value_placeholder')
30
+ %span.property__note= "Example: <a href='/manuals'>Download Manuals</a>"
31
+ %td.align-center -
@@ -0,0 +1,31 @@
1
+ .section.section--additional-details
2
+ %h2= "Additional Details"
3
+
4
+ %table
5
+ %thead
6
+ %tr
7
+ %th= t('workarea.admin.catalog_products.edit.details.name')
8
+ %th= "Content"
9
+ %th.align-center= t('workarea.admin.actions.delete')
10
+ %tbody.bottom-align
11
+ - variant.additional_details.each do |name, value|
12
+ %tr
13
+ %td
14
+ .property
15
+ = label_tag "details_#{name}" do
16
+ #{name}
17
+ %td
18
+ .property
19
+ = hidden_field_tag 'additional_details[]', name, id: nil
20
+ = text_area_tag 'additional_details[]', value, class: 'text-box text-box--i18n', id: nil
21
+ %td.align-center= check_box_tag 'additional_details_to_remove[]', name, false, id: nil, title: "#{t('workarea.admin.actions.delete')}: #{name} #{value}"
22
+ %tr{ data: { cloneable_row: '' } }
23
+ %td
24
+ .property
25
+ = text_field_tag 'new_additional_details[]', nil, id: nil, class: 'text-box text-box--i18n', title: t('workarea.admin.catalog_products.edit.details.new_attribute_name'), placeholder: t('workarea.admin.catalog_products.edit.details.new_attribute_name_placeholder')
26
+ %span.property__note= "Example: User Manual"
27
+ %td
28
+ .property
29
+ = text_area_tag 'new_additional_details[]', nil, id: nil, class: 'text-box text-box--i18n', title: t('workarea.admin.catalog_products.edit.details.new_attribute_value'), placeholder: t('workarea.admin.catalog_products.edit.details.new_attribute_value_placeholder')
30
+ %span.property__note= "Example: <a href='/manuals'>Download Manuals</a>"
31
+ %td.align-center -
@@ -0,0 +1,114 @@
1
+ - @page_title = t('workarea.admin.create_catalog_products.details.page_title', product_name: @product.name)
2
+
3
+ .view
4
+ .view__header
5
+ .grid.grid--right
6
+ .grid__cell.grid__cell--50
7
+ .view__heading
8
+ %h1.heading.heading--no-margin= t('workarea.admin.create_catalog_products.details.add_details', product_name: @product.name)
9
+ %p= link_to t('workarea.admin.create_catalog_products.details.or_skip_this'), content_create_catalog_product_path(@product)
10
+ .grid__cell.grid__cell--25
11
+ = render_aux_navigation_for(@product, html_options: { target: @product.id })
12
+
13
+ .view__container.view__container--narrow
14
+ = form_tag save_details_create_catalog_product_path(@product), method: 'post' do
15
+ .grid.grid--huge
16
+ .grid__cell.grid__cell--50-at-medium
17
+ .section
18
+ %h2= t('workarea.admin.create_catalog_products.details.filters')
19
+
20
+ %table
21
+ %tbody
22
+ - @filters.each do |name, value|
23
+ %tr
24
+ %td
25
+ .property
26
+ = text_field_tag 'filters[]', name, class: 'text-box text-box--i18n', title: 'New Filter Name', placeholder: 'Name', pattern: Workarea.config.product_filter_input_validation_pattern, id: nil
27
+ %td
28
+ .property
29
+ = text_field_tag 'filters[]', hash_editing_value(value), class: 'text-box text-box--i18n', title: 'New Filter Value', placeholder: 'Value', id: nil
30
+
31
+ %tr{ data: { cloneable_row: '' } }
32
+ %td
33
+ .property
34
+ = text_field_tag 'filters[]', nil, class: 'text-box text-box--i18n', title: 'New Filter Name', placeholder: 'Name', pattern: Workarea.config.product_filter_input_validation_pattern, id: nil
35
+ %span.property__note= t('workarea.admin.create_catalog_products.details.example_color')
36
+ %td
37
+ .property
38
+ = text_field_tag 'filters[]', nil, class: 'text-box text-box--i18n', title: 'New Filter Value', placeholder: 'Value', id: nil
39
+ %span.property__note= t('workarea.admin.create_catalog_products.details.comma_separated_red_green')
40
+
41
+ .grid__cell.grid__cell--50-at-medium
42
+ .section
43
+ %h2= t('workarea.admin.create_catalog_products.details.details')
44
+
45
+ %table
46
+ %tbody
47
+ - @product.details.each do |name, value|
48
+ %tr
49
+ %td
50
+ .property
51
+ = text_field_tag 'details[]', name, class: 'text-box text-box--i18n', title: 'Name', placeholder: 'Name', id: nil
52
+ %td
53
+ .property
54
+ = text_field_tag 'details[]', hash_editing_value(value), class: 'text-box text-box--i18n', title: 'Value', placeholder: 'Value', id: nil
55
+ %tr{ data: { cloneable_row: '' } }
56
+ %td
57
+ .property
58
+ = text_field_tag 'details[]', nil, class: 'text-box text-box--i18n', title: 'Name', placeholder: 'Name', id: nil
59
+ %span.property__note= t('workarea.admin.create_catalog_products.details.example_manufactured')
60
+ %td
61
+ .property
62
+ = text_field_tag 'details[]', nil, class: 'text-box text-box--i18n', title: 'Value', placeholder: 'Value', id: nil
63
+ %span.property__note= t('workarea.admin.create_catalog_products.details.example_usa')
64
+
65
+ .grid__cell
66
+ .section
67
+ %h2= "Additional Details"
68
+
69
+ %table
70
+ %tbody.bottom-align
71
+ - @product.additional_details.each do |name, value|
72
+ %tr
73
+ %td
74
+ .property
75
+ = text_field_tag 'additional_details[]', name, class: 'text-box text-box--i18n', title: 'Name', placeholder: 'Name', id: nil
76
+ %td
77
+ .property
78
+ = text_area_tag 'additional_details[]', hash_editing_value(value), class: 'text-box text-box--i18n', title: 'Value', placeholder: 'Value', id: nil
79
+ %tr{ data: { cloneable_row: '' } }
80
+ %td
81
+ .property
82
+ = text_field_tag 'additional_details[]', nil, class: 'text-box text-box--i18n', title: 'Name', placeholder: 'Name', id: nil
83
+ %span.property__note= "Example: User Manual"
84
+ %td
85
+ .property
86
+ = text_area_tag 'additional_details[]', nil, class: 'text-box text-box--i18n', title: 'Value', placeholder: 'Value', id: nil
87
+ %span.property__note= "Example: <a href='/manuals'>Download Manuals</a>"
88
+
89
+ .workflow-bar
90
+ .grid.grid--middle
91
+ .grid__cell.grid__cell--20
92
+ = link_to t('workarea.admin.create_catalog_products.details.cancel'), catalog_product_path(@product), class: 'workflow-bar__button workflow-bar__button--delete', data: { method: 'delete', confirm: t('workarea.admin.create_catalog_products.are_you_sure_all_work_on_this_product_will_be_lost') }
93
+
94
+ .grid__cell.grid__cell--60
95
+
96
+ %ol.workflow-bar__steps
97
+ %li.workflow-bar__step
98
+ 1) #{link_to t('workarea.admin.create_catalog_products.steps.setup'), edit_create_catalog_product_path(@product)}
99
+ %li.workflow-bar__step
100
+ 2) #{link_to t('workarea.admin.create_catalog_products.steps.variants'), variants_create_catalog_product_path(@product)}
101
+ %li.workflow-bar__step
102
+ 2) #{link_to t('workarea.admin.create_catalog_products.steps.images'), images_create_catalog_product_path(@product)}
103
+ %li.workflow-bar__step
104
+ %strong 4) #{t('workarea.admin.create_catalog_products.steps.details')}
105
+ %li.workflow-bar__step
106
+ 5) #{t('workarea.admin.create_catalog_products.steps.content')}
107
+ %li.workflow-bar__step
108
+ 6) #{t('workarea.admin.create_catalog_products.steps.categorization')}
109
+ %li.workflow-bar__step
110
+ 7) #{t('workarea.admin.create_catalog_products.steps.publish')}
111
+
112
+ .grid__cell.grid__cell--20
113
+ .grid.grid--auto.grid--right.grid--middle
114
+ = button_tag t('workarea.admin.create_catalog_products.details.save_details_and_continue'), value: 'save_details', class: 'workflow-bar__button workflow-bar__button--create'
@@ -0,0 +1,8 @@
1
+ Workarea.append_partials(
2
+ 'admin.additional_product_details_information',
3
+ 'workarea/admin/catalog_products/additional_details'
4
+ )
5
+ Workarea.append_partials(
6
+ 'admin.additional_variant_information_fields',
7
+ 'workarea/admin/catalog_variants/additional_details'
8
+ )
@@ -1,5 +1,5 @@
1
1
  module Workarea
2
2
  module ProductAdditionalDetails
3
- VERSION = "0.0.0".freeze
3
+ VERSION = "2.0.3".freeze
4
4
  end
5
5
  end
@@ -0,0 +1,13 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ decorate Catalog::ProductTest, with: :product_additional_details do
5
+ # Define additional tests based on new functionality or
6
+ # override tests originally defined in the decorated class for
7
+ # changes that alter default behavior.
8
+ #
9
+ # While calling super to extend a test case is possible, it is
10
+ # recommended that you add a new test or completely override an
11
+ # existing test to avoid ambiguity in your test suite.
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ decorate UserTest, with: :product_additional_details do
5
+ # Define additional tests based on new functionality or
6
+ # override tests originally defined in the decorated class for
7
+ # changes that alter default behavior.
8
+ #
9
+ # While calling super to extend a test case is possible, it is
10
+ # recommended that you add a new test or completely override an
11
+ # existing test to avoid ambiguity in your test suite.
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ decorate HashUpdateTest, with: :product_additional_details do
5
+ # Define additional tests based on new functionality or
6
+ # override tests originally defined in the decorated class for
7
+ # changes that alter default behavior.
8
+ #
9
+ # While calling super to extend a test case is possible, it is
10
+ # recommended that you add a new test or completely override an
11
+ # existing test to avoid ambiguity in your test suite.
12
+ end
13
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: workarea-product_additional_details
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gunasekaran Raja
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-24 00:00:00.000000000 Z
11
+ date: 2020-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: workarea
@@ -41,14 +41,26 @@ files:
41
41
  - app/assets/images/workarea/storefront/product_additional_details/.keep
42
42
  - app/assets/javascripts/workarea/admin/product_additional_details/.keep
43
43
  - app/assets/javascripts/workarea/storefront/product_additional_details/.keep
44
+ - app/assets/stylesheets/workarea/admin/base/_tables.scss
44
45
  - app/assets/stylesheets/workarea/admin/product_additional_details/.keep
45
46
  - app/assets/stylesheets/workarea/storefront/product_additional_details/.keep
46
47
  - app/controllers/.keep
48
+ - app/controllers/workarea/admin/catalog_products_controller.decorator
49
+ - app/controllers/workarea/admin/catalog_variants_controller.decorator
50
+ - app/controllers/workarea/admin/create_catalog_products_controller.decorator
47
51
  - app/helpers/.keep
48
52
  - app/mailers/.keep
49
53
  - app/models/.keep
54
+ - app/models/workarea/catalog/product.decorator
55
+ - app/models/workarea/catalog/variant.decorator
56
+ - app/models/workarea/search/storefront/product/text.rb
57
+ - app/services/workarea/hash_update.decorator
50
58
  - app/views/.keep
59
+ - app/views/workarea/admin/catalog_products/_additional_details.html.haml
60
+ - app/views/workarea/admin/catalog_variants/_additional_details.html.haml
61
+ - app/views/workarea/admin/create_catalog_products/details.html.haml
51
62
  - bin/rails
63
+ - config/initializers/appends.rb
52
64
  - config/initializers/workarea.rb
53
65
  - config/routes.rb
54
66
  - lib/workarea/product_additional_details.rb
@@ -96,8 +108,11 @@ files:
96
108
  - test/dummy/db/seeds.rb
97
109
  - test/dummy/lib/assets/.keep
98
110
  - test/dummy/log/.keep
111
+ - test/models/workarea/catalog/product_test.decorator
112
+ - test/models/workarea/user_test.decorator
99
113
  - test/teaspoon_env.rb
100
114
  - test/test_helper.rb
115
+ - test/workarea/hash_update_test.decorator
101
116
  - workarea-product_additional_details.gemspec
102
117
  homepage: https://github.com/trikatechnologies/workarea-product_additional_details
103
118
  licenses: