spree_admin 5.5.0 → 5.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/tailwind/spree/admin/components/_dialogs.css +1 -1
- data/app/views/spree/admin/price_rules/forms/_channel_rule.html.erb +7 -0
- data/app/views/spree/admin/products/form/_publishing.html.erb +50 -33
- data/app/views/spree/admin/shared/_new_item_dropdown.html.erb +2 -2
- data/lib/spree/admin/tailwind_helper.rb +28 -6
- data/lib/tasks/tailwind.rake +41 -38
- metadata +7 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fe7bbf921b79a573c2d091927442a90d3f7305fa2c8024b34c3a75ee9a0d3b26
|
|
4
|
+
data.tar.gz: 72fd353cee9a2dfba89b70cbeb09e1e2260b4876d468d7d34c0435aeeca2ec3a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d5c8f4935b961a62800280b15ea76248e9f3c132ca7aa02ef33952953bbe65efec1595f87f028aa4d41ea5446b7feb841029e9b761ac9b093e1af4cda4e26fd0
|
|
7
|
+
data.tar.gz: a26a759b7ed7f13c37eaf09aa9a18e5edacc46d0b6fc4fd23bc8c88a5782f8ae4a02ad19c391e90f5d474157c7f21a716376f249aa3c9bd402377b23caa1326e
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
.dialog-footer {
|
|
171
|
-
@apply
|
|
171
|
+
@apply shrink-0 p-4 flex gap-2 items-center justify-between border-t border-gray-100 bg-gray-25;
|
|
172
172
|
border-radius: 0 0 calc(var(--radius-2xl) - 1px) calc(var(--radius-2xl) - 1px);
|
|
173
173
|
}
|
|
174
174
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<div class="form-group">
|
|
2
|
+
<%= f.label :preferred_channel_ids, Spree.t(:channels) %>
|
|
3
|
+
<%= f.select :preferred_channel_ids,
|
|
4
|
+
current_store.channels.order(:name).pluck(:name, :id),
|
|
5
|
+
{ selected: f.object.preferred_channel_ids },
|
|
6
|
+
{ multiple: true, data: { controller: 'autocomplete-select' } } %>
|
|
7
|
+
</div>
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
tz_help = Spree.t('admin.datetime_field_timezone_help', zone: store_timezone.name)
|
|
19
19
|
store_channels = current_store.channels.order(:name).to_a
|
|
20
20
|
publications_by_channel = @product.product_publications.includes(:channel).index_by(&:channel_id)
|
|
21
|
+
can_manage_publications = can?(:manage, Spree::ProductPublication)
|
|
21
22
|
|
|
22
23
|
# Build one record per store channel: the existing publication when
|
|
23
24
|
# attached, or a fresh ProductPublication when not. Stable channel-keyed
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
<div class="card mb-6" data-controller="product-publishing">
|
|
34
35
|
<div class="card-header d-flex align-items-center justify-content-between">
|
|
35
36
|
<h6 class="card-title mb-0"><%= Spree.t('admin.publishing.title') %></h6>
|
|
36
|
-
<% if store_channels.any? %>
|
|
37
|
+
<% if store_channels.any? && can_manage_publications %>
|
|
37
38
|
<button type="button"
|
|
38
39
|
class="btn btn-sm btn-outline-secondary"
|
|
39
40
|
data-action="product-publishing#toggleManage">
|
|
@@ -47,6 +48,7 @@
|
|
|
47
48
|
<p class="text-xs text-muted mb-0"><%= Spree.t('admin.publishing.no_channels') %></p>
|
|
48
49
|
<% else %>
|
|
49
50
|
<%# ---- Manage panel (hidden by default) ---- %>
|
|
51
|
+
<% if can_manage_publications %>
|
|
50
52
|
<div class="d-none flex flex-col gap-2 mb-3" data-product-publishing-target="manage">
|
|
51
53
|
<p class="text-xs text-muted mb-1"><%= Spree.t('admin.publishing.manage_description') %></p>
|
|
52
54
|
<% channel_rows.each_with_index do |(channel, publication), index| %>
|
|
@@ -73,6 +75,7 @@
|
|
|
73
75
|
<% end %>
|
|
74
76
|
<% end %>
|
|
75
77
|
</div>
|
|
78
|
+
<% end %>
|
|
76
79
|
|
|
77
80
|
<%# ---- Per-publication scheduling rows ---- %>
|
|
78
81
|
<% if publications_by_channel.empty? %>
|
|
@@ -80,43 +83,57 @@
|
|
|
80
83
|
<% else %>
|
|
81
84
|
<% channel_rows.each_with_index do |(channel, publication), index| %>
|
|
82
85
|
<% next unless publication.persisted? %>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<
|
|
86
|
-
<
|
|
87
|
-
<div class="flex
|
|
88
|
-
<
|
|
89
|
-
|
|
86
|
+
<% if can_manage_publications %>
|
|
87
|
+
<%= f.fields_for :legacy_product_publications, publication, child_index: index do |pf| %>
|
|
88
|
+
<details class="publication-row group rounded -mx-2 px-2 hover:bg-gray-50">
|
|
89
|
+
<summary class="flex items-start justify-between gap-3 py-2 cursor-pointer" style="list-style: none;">
|
|
90
|
+
<div class="flex min-w-0 flex-1 flex-col gap-0.5">
|
|
91
|
+
<div class="flex items-center gap-2">
|
|
92
|
+
<span class="truncate text-sm font-medium"><%= channel.name %></span>
|
|
93
|
+
<%= publication_status_badge(@product.status, publication) %>
|
|
94
|
+
</div>
|
|
95
|
+
<span class="text-xs text-muted">
|
|
96
|
+
<%= publication_caption(@product.status, publication, current_store) %>
|
|
97
|
+
</span>
|
|
90
98
|
</div>
|
|
91
|
-
<span class="
|
|
92
|
-
<%=
|
|
99
|
+
<span class="shrink-0 mt-1 opacity-0 transition-opacity group-hover:opacity-100 text-muted">
|
|
100
|
+
<%= icon('pencil', class: 'h-3.5 w-3.5') %>
|
|
93
101
|
</span>
|
|
102
|
+
</summary>
|
|
103
|
+
<div class="mt-2 ps-2 pb-2 flex flex-col gap-3">
|
|
104
|
+
<div>
|
|
105
|
+
<%= pf.label :published_at,
|
|
106
|
+
Spree.t('admin.publishing.published_at_label'),
|
|
107
|
+
class: 'form-label text-xs mb-1' %>
|
|
108
|
+
<%= pf.datetime_field :published_at,
|
|
109
|
+
value: to_store_local.call(publication.published_at),
|
|
110
|
+
class: 'form-control form-control-sm' %>
|
|
111
|
+
<small class="text-muted text-xs"><%= tz_help %></small>
|
|
112
|
+
</div>
|
|
113
|
+
<div>
|
|
114
|
+
<%= pf.label :unpublished_at,
|
|
115
|
+
Spree.t('admin.publishing.unpublished_at_label'),
|
|
116
|
+
class: 'form-label text-xs mb-1' %>
|
|
117
|
+
<%= pf.datetime_field :unpublished_at,
|
|
118
|
+
value: to_store_local.call(publication.unpublished_at),
|
|
119
|
+
class: 'form-control form-control-sm' %>
|
|
120
|
+
<small class="text-muted text-xs"><%= tz_help %></small>
|
|
121
|
+
</div>
|
|
94
122
|
</div>
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
<div class="
|
|
100
|
-
<div>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
class: 'form-label text-xs mb-1' %>
|
|
104
|
-
<%= pf.datetime_field :published_at,
|
|
105
|
-
value: to_store_local.call(publication.published_at),
|
|
106
|
-
class: 'form-control form-control-sm' %>
|
|
107
|
-
<small class="text-muted text-xs"><%= tz_help %></small>
|
|
108
|
-
</div>
|
|
109
|
-
<div>
|
|
110
|
-
<%= pf.label :unpublished_at,
|
|
111
|
-
Spree.t('admin.publishing.unpublished_at_label'),
|
|
112
|
-
class: 'form-label text-xs mb-1' %>
|
|
113
|
-
<%= pf.datetime_field :unpublished_at,
|
|
114
|
-
value: to_store_local.call(publication.unpublished_at),
|
|
115
|
-
class: 'form-control form-control-sm' %>
|
|
116
|
-
<small class="text-muted text-xs"><%= tz_help %></small>
|
|
123
|
+
</details>
|
|
124
|
+
<% end %>
|
|
125
|
+
<% else %>
|
|
126
|
+
<div class="publication-row -mx-2 px-2">
|
|
127
|
+
<div class="flex min-w-0 flex-1 flex-col gap-0.5 py-2">
|
|
128
|
+
<div class="flex items-center gap-2">
|
|
129
|
+
<span class="truncate text-sm font-medium"><%= channel.name %></span>
|
|
130
|
+
<%= publication_status_badge(@product.status, publication) %>
|
|
117
131
|
</div>
|
|
132
|
+
<span class="text-xs text-muted">
|
|
133
|
+
<%= publication_caption(@product.status, publication, current_store) %>
|
|
134
|
+
</span>
|
|
118
135
|
</div>
|
|
119
|
-
</
|
|
136
|
+
</div>
|
|
120
137
|
<% end %>
|
|
121
138
|
<% end %>
|
|
122
139
|
<% end %>
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
|
|
22
22
|
<%= invite_vendor_button(class: 'dropdown-item') if defined?(invite_vendor_button) %>
|
|
23
23
|
|
|
24
|
-
<% if can?(:create, Spree::Store) && Spree.root_domain.present? %>
|
|
24
|
+
<% if can?(:create, Spree::Store) && Spree.root_domain.present? && spree.respond_to?(:new_admin_store_path) %>
|
|
25
25
|
<div class="dropdown-divider"></div>
|
|
26
26
|
|
|
27
27
|
<%= link_to_with_icon 'building-store', Spree.t(:new_store), spree.new_admin_store_path, class: 'dropdown-item' %>
|
|
28
28
|
<% end %>
|
|
29
29
|
<% end %>
|
|
30
|
-
<% end %>
|
|
30
|
+
<% end %>
|
|
@@ -47,20 +47,42 @@ module Spree
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
# [relative dir, glob] pairs Tailwind scans for utility classes.
|
|
51
|
+
SOURCE_PATHS = [
|
|
52
|
+
["app/views/spree/admin", "**/*.erb"],
|
|
53
|
+
["app/helpers/spree/admin", "**/*.rb"],
|
|
54
|
+
["app/javascript/spree/admin", "**/*.js"]
|
|
55
|
+
].freeze
|
|
56
|
+
|
|
50
57
|
def engine_sources(engine)
|
|
51
58
|
root = engine.root.to_s
|
|
52
|
-
source_paths = [
|
|
53
|
-
["app/views/spree/admin", "**/*.erb"],
|
|
54
|
-
["app/helpers/spree/admin", "**/*.rb"],
|
|
55
|
-
["app/javascript/spree/admin", "**/*.js"]
|
|
56
|
-
]
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
SOURCE_PATHS.filter_map do |dir, pattern|
|
|
59
61
|
full_dir = File.join(root, dir)
|
|
60
62
|
%(@source "#{full_dir}/#{pattern}";) if File.directory?(full_dir)
|
|
61
63
|
end
|
|
62
64
|
end
|
|
63
65
|
|
|
66
|
+
# Every template/CSS glob that affects the compiled admin CSS, across all
|
|
67
|
+
# Spree engines plus the host app. Used by watch mode to poll for changes
|
|
68
|
+
# (OS file-system events don't cross a Docker bind mount from a macOS host).
|
|
69
|
+
#
|
|
70
|
+
# @return [Array<String>] absolute Dir.glob patterns
|
|
71
|
+
def source_globs
|
|
72
|
+
roots = spree_engines.map { |engine| engine.root.to_s }
|
|
73
|
+
roots << Rails.root.to_s
|
|
74
|
+
|
|
75
|
+
template_globs = roots.product(SOURCE_PATHS).map do |root, (dir, pattern)|
|
|
76
|
+
File.join(root, dir, pattern)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
css_globs = [engine_css_path.to_s, input_path.dirname.to_s].map do |dir|
|
|
80
|
+
File.join(dir, "**", "*.css")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
(template_globs + css_globs).uniq
|
|
84
|
+
end
|
|
85
|
+
|
|
64
86
|
def write_resolved_css
|
|
65
87
|
FileUtils.mkdir_p(resolved_input_path.dirname)
|
|
66
88
|
File.write(resolved_input_path, resolved_input_css)
|
data/lib/tasks/tailwind.rake
CHANGED
|
@@ -29,54 +29,57 @@ namespace :spree do
|
|
|
29
29
|
task watch: :environment do
|
|
30
30
|
require "tailwindcss/ruby"
|
|
31
31
|
|
|
32
|
-
begin
|
|
33
|
-
require "listen"
|
|
34
|
-
rescue LoadError
|
|
35
|
-
puts "ERROR: The 'listen' gem is required for watch mode."
|
|
36
|
-
puts "Add it to your Gemfile in the development group:"
|
|
37
|
-
puts ""
|
|
38
|
-
puts " group :development do"
|
|
39
|
-
puts " gem 'listen', '>= 3.0'"
|
|
40
|
-
puts " end"
|
|
41
|
-
puts ""
|
|
42
|
-
exit 1
|
|
43
|
-
end
|
|
44
|
-
|
|
45
32
|
output_path = Spree::Admin::TailwindHelper.output_path
|
|
46
33
|
FileUtils.mkdir_p(output_path.dirname)
|
|
47
34
|
|
|
48
|
-
|
|
49
|
-
|
|
35
|
+
resolved_path = Spree::Admin::TailwindHelper.resolved_input_path
|
|
36
|
+
|
|
37
|
+
# One-shot Tailwind build. Polling drives recompilation instead of
|
|
38
|
+
# Tailwind's own --watch: its file watching (like the `listen` gem's)
|
|
39
|
+
# relies on OS file-system events, which don't cross a Docker bind mount
|
|
40
|
+
# from a macOS host, so a host-side template edit would never rebuild.
|
|
41
|
+
build = lambda do
|
|
42
|
+
Spree::Admin::TailwindHelper.write_resolved_css
|
|
43
|
+
system(Tailwindcss::Ruby.executable, "-i", resolved_path.to_s, "-o", output_path.to_s)
|
|
44
|
+
# system doesn't raise on a non-zero exit, so surface build failures
|
|
45
|
+
# (invalid CSS, missing binary) — otherwise a broken rebuild is silent.
|
|
46
|
+
warn "[tailwind watch] build failed (exit #{$?.exitstatus})" unless $?.success?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
source_mtimes = lambda do
|
|
50
|
+
Spree::Admin::TailwindHelper.source_globs.each_with_object({}) do |glob, acc|
|
|
51
|
+
Dir.glob(glob).each do |file|
|
|
52
|
+
acc[file] = File.mtime(file) rescue next
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
50
57
|
puts "Watching Spree Admin Tailwind CSS for changes..."
|
|
51
58
|
puts " Host input: #{Spree::Admin::TailwindHelper.input_path}"
|
|
52
59
|
puts " Engine CSS: #{Spree::Admin::TailwindHelper.engine_css_path}"
|
|
53
60
|
puts " Resolved: #{resolved_path}"
|
|
54
61
|
puts " Output: #{output_path}"
|
|
55
62
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
build.call
|
|
64
|
+
previous = source_mtimes.call
|
|
65
|
+
|
|
66
|
+
loop do
|
|
67
|
+
sleep 1
|
|
68
|
+
begin
|
|
69
|
+
current = source_mtimes.call
|
|
70
|
+
next if current == previous
|
|
71
|
+
|
|
72
|
+
changed = (current.keys | previous.keys).select { |f| current[f] != previous[f] }
|
|
73
|
+
.map { |f| File.basename(f) }.uniq.first(5).join(", ")
|
|
74
|
+
previous = current
|
|
75
|
+
puts "\n[#{Time.now.strftime('%H:%M:%S')}] Sources changed: #{changed} — rebuilding..."
|
|
76
|
+
build.call
|
|
77
|
+
rescue => e
|
|
78
|
+
# A transient read/build error (e.g. a source file caught mid-save)
|
|
79
|
+
# must not kill the watch loop — log and keep polling.
|
|
80
|
+
warn "[tailwind watch] rebuild failed: #{e.class}: #{e.message}"
|
|
81
|
+
end
|
|
68
82
|
end
|
|
69
|
-
listener.start
|
|
70
|
-
|
|
71
|
-
# Run Tailwind in watch mode (this blocks)
|
|
72
|
-
command = [
|
|
73
|
-
Tailwindcss::Ruby.executable,
|
|
74
|
-
"-i", resolved_path.to_s,
|
|
75
|
-
"-o", output_path.to_s,
|
|
76
|
-
"--watch"
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
system(*command)
|
|
80
83
|
end
|
|
81
84
|
end
|
|
82
85
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spree_admin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.5.
|
|
4
|
+
version: 5.5.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vendo Connect Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06
|
|
11
|
+
date: 2026-07-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: spree
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 5.5.
|
|
19
|
+
version: 5.5.2
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 5.5.
|
|
26
|
+
version: 5.5.2
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: active_link_to
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -768,6 +768,7 @@ files:
|
|
|
768
768
|
- app/views/spree/admin/price_lists/update.turbo_stream.erb
|
|
769
769
|
- app/views/spree/admin/price_rules/_price_rule.html.erb
|
|
770
770
|
- app/views/spree/admin/price_rules/edit.html.erb
|
|
771
|
+
- app/views/spree/admin/price_rules/forms/_channel_rule.html.erb
|
|
771
772
|
- app/views/spree/admin/price_rules/forms/_customer_group_rule.html.erb
|
|
772
773
|
- app/views/spree/admin/price_rules/forms/_market_rule.html.erb
|
|
773
774
|
- app/views/spree/admin/price_rules/forms/_user_rule.html.erb
|
|
@@ -1172,9 +1173,9 @@ licenses:
|
|
|
1172
1173
|
- BSD-3-Clause
|
|
1173
1174
|
metadata:
|
|
1174
1175
|
bug_tracker_uri: https://github.com/spree/spree/issues
|
|
1175
|
-
changelog_uri: https://github.com/spree/spree/releases/tag/v5.5.
|
|
1176
|
+
changelog_uri: https://github.com/spree/spree/releases/tag/v5.5.2
|
|
1176
1177
|
documentation_uri: https://docs.spreecommerce.org/
|
|
1177
|
-
source_code_uri: https://github.com/spree/spree/tree/v5.5.
|
|
1178
|
+
source_code_uri: https://github.com/spree/spree/tree/v5.5.2
|
|
1178
1179
|
post_install_message:
|
|
1179
1180
|
rdoc_options: []
|
|
1180
1181
|
require_paths:
|