active_admin_theme 3.1.1 → 3.2.0

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.
@@ -3,6 +3,132 @@ require "active_admin_theme/version"
3
3
  module ActiveAdminTheme
4
4
  module Rails
5
5
  class Engine < ::Rails::Engine
6
+ # Register the server clock once AA is available. server_clock.js (shipped
7
+ # in this gem) ticks li#servertime in #utility_nav and reads the server
8
+ # instant from [data-servertime]; here we render both server-side, per
9
+ # namespace, so every consumer gets the clock without reimplementing it.
10
+ # after :load_config_initializers, or hosts loading AA from a config
11
+ # initializer (gem "activeadmin", require: false) fail the defined?
12
+ # check and silently get no clock — engine initializers otherwise run
13
+ # before the host's config/initializers.
14
+ initializer "active_admin_theme.server_clock", after: :load_config_initializers do
15
+ if defined?(::ActiveAdmin)
16
+ ActiveAdminTheme.install!
17
+ else
18
+ # Evaluated once; a host requiring activeadmin even later (routes.rb,
19
+ # an ENV-gated engine) gets no theme at all — say so instead of
20
+ # silently shipping a README-promised feature that never appears.
21
+ ::Rails.logger&.warn(
22
+ "active_admin_theme: ActiveAdmin was not loaded when the engine " \
23
+ "initialized; the utility-nav clock and logout handling are " \
24
+ "disabled. Require \"active_admin\" no later than config/initializers."
25
+ )
26
+ end
27
+ end
6
28
  end
7
29
  end
8
- end
30
+
31
+ # Opt-out for the restored current-user item. Unlike logout (which AA turns
32
+ # off per namespace via logout_link_path = nil), AA has no switch short of
33
+ # unsetting current_user_method — which also breaks authorization — and
34
+ # Menu has no removal API, so hosts that deliberately run a user-link-free
35
+ # header (e.g. display_name would leak an email) set this in an initializer:
36
+ # ActiveAdminTheme.add_current_user = false
37
+ class << self
38
+ attr_accessor :add_current_user
39
+ end
40
+ self.add_current_user = true
41
+
42
+ # Add a utility-nav clock item (and ensure a logout item) to every AA namespace.
43
+ #
44
+ # data-servertime must be fresh on every request, but only a menu item's
45
+ # :label/:url/:if are evaluated per request — :html_options is captured once at
46
+ # build time. So the instant is embedded in the label as html_safe markup
47
+ # rather than an html_option. The label is "YYYY MM DD HH MM SS ZONE" (exactly
48
+ # what server_clock.js parses) on an inner span; the JS overwrites the visible
49
+ # text each tick. Timezone comes from the host app's Time.current/Time.zone.
50
+ def self.install!
51
+ # after_load fires on every ActiveAdmin.load! (each dev reload), and each
52
+ # build_menu call registers a before_build callback that MenuCollection#clear!
53
+ # never removes — so register once per namespace or callbacks pile up for
54
+ # the life of the process. Namespace objects and their MenuCollection
55
+ # survive unload! (it only clears the built menus), so once is enough.
56
+ seen = {}.compare_by_identity
57
+ register = lambda do |namespace|
58
+ next if seen[namespace]
59
+ seen[namespace] = true
60
+ namespace.build_menu(:utility_navigation) do |menu|
61
+ # A consumer item with the same id wins, but NOT through these
62
+ # guards: before_build unshifts, so the LAST registration runs
63
+ # first, and consumer hooks (config/initializers) subscribe before
64
+ # this engine's initializer — on a production first load THIS
65
+ # callback runs first against an empty menu and the guards all
66
+ # pass. What protects consumer overrides is Menu#_add replacing by
67
+ # id when their callback runs afterwards. The guards only matter
68
+ # from the second dev reload on, when consumer items are already
69
+ # present — do not tighten them into the primary mechanism.
70
+ unless menu["servertime"]
71
+ menu.add id: "servertime",
72
+ priority: 99_990,
73
+ url: -> {},
74
+ # same guard both default utility items carry — the nav
75
+ # stays empty for anonymous visitors, as it was pre-theme
76
+ if: :current_active_admin_user?,
77
+ label: lambda {
78
+ now = Time.current
79
+ data = now.strftime("%Y %m %d %H %M %S %Z")
80
+ shown = now.strftime("%Y %b %d %H:%M:%S %Z")
81
+ # epoch + IANA zone let the JS re-apply the server
82
+ # zone's offset on every tick (DST included); the
83
+ # wall-clock attribute stays as the documented contract
84
+ # for host-rendered elements and older scripts.
85
+ # Time.zone is nil under Time.use_zone(nil) — the
86
+ # common around_action(user.time_zone) pattern with a
87
+ # nil column — while Time.current still works; skip the
88
+ # precise attributes then instead of 500ing the page.
89
+ tz = Time.zone
90
+ precise = tz ? %( data-servertime-epoch="#{now.to_i}" data-servertime-zone="#{tz.tzinfo.identifier}") : ""
91
+ %(<span data-servertime="#{data}"#{precise}>#{shown}</span>).html_safe
92
+ }
93
+ end
94
+ # Claiming :utility_navigation stops AA's build_default_utility_nav
95
+ # (it returns early once the menu exists), so restore the default
96
+ # current-user item it would have added. No-op when the host has no
97
+ # current_user_method, exactly like the default nav.
98
+ if ActiveAdminTheme.add_current_user && !menu["current_user"]
99
+ namespace.add_current_user_to_menu(menu)
100
+ end
101
+ # Opting out is ActiveAdmin's own per-namespace switch, not a theme
102
+ # flag: config.logout_link_path = nil makes add_logout_button_to_menu
103
+ # a no-op (AA guards on `if logout_link_path`). Hosts with custom
104
+ # auth and no logout route — where rendering the default item would
105
+ # public_send a missing helper and 500 — set exactly that.
106
+ # The wigu-logout class (lands on the <a> — AA passes html_options to
107
+ # link_to) scopes the stylesheet's icon treatment to THIS item, so a
108
+ # consumer-rendered logout with its own label keeps its text. The
109
+ # aria-label is the accessible name: the stylesheet hides the link
110
+ # text with font-size: 0, which some screen readers prune from the
111
+ # accessibility tree. html_options are captured at menu-build time, so
112
+ # the label uses the locale active then — good enough for a nav icon.
113
+ unless menu["logout"]
114
+ namespace.add_logout_button_to_menu(
115
+ menu, 99_999,
116
+ class: "wigu-logout", "aria-label": I18n.t("active_admin.logout")
117
+ )
118
+ end
119
+ end
120
+ end
121
+
122
+ ::ActiveAdmin.after_load do |app|
123
+ app.namespaces.each(&register)
124
+ end
125
+ # Production fires after_load exactly once (load! gates on @@loaded), so a
126
+ # namespace created later — e.g. another engine's later-subscribed hook
127
+ # registering a resource into a new namespace — would keep AA's stock
128
+ # default nav, inconsistently with its siblings. Namespace creation has
129
+ # its own notification; theme late arrivals through it.
130
+ ActiveSupport::Notifications.subscribe(::ActiveAdmin::Namespace::RegisterEvent) do |*args|
131
+ register.call(args.last[:active_admin_namespace])
132
+ end
133
+ end
134
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_admin_theme
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.1
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Fedoronchuk
@@ -40,6 +40,10 @@ extra_rdoc_files: []
40
40
  files:
41
41
  - LICENSE.txt
42
42
  - README.md
43
+ - app/assets/javascripts/wigu/all.js
44
+ - app/assets/javascripts/wigu/scrollbar_width.js
45
+ - app/assets/javascripts/wigu/server_clock.js
46
+ - app/assets/javascripts/wigu/table_crisscross.js
43
47
  - app/assets/javascripts/wigu/theme_toggle.js
44
48
  - app/assets/stylesheets/wigu/active_admin_theme.scss
45
49
  - lib/active_admin_theme.rb