glib-web 7.0.1 → 7.1.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.
- checksums.yaml +4 -4
- data/app/controllers/concerns/glib/params/allowlist.rb +11 -3
- data/app/controllers/glib/errors_controller.rb +8 -2
- data/app/helpers/glib/json_ui/action_builder.rb +2 -9
- data/app/helpers/glib/json_ui/view_builder/panels.rb +0 -41
- data/app/helpers/glib/json_ui/view_builder.rb +0 -6
- data/app/views/json_ui/garage/test_page/bottom_banners.json.jbuilder +69 -0
- data/app/views/json_ui/garage/test_page/web.json.jbuilder +12 -7
- data/app/views/json_ui/garage/views/misc.json.jbuilder +10 -6
- data/lib/glib/json_ui/config.rb +8 -9
- metadata +9 -4
- data/app/helpers/glib/json_ui/action_builder/global_states.rb +0 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e178f9febdf54e054c6415f98e2dba1168d13ca1eea53c3a2e4c7aba62a434e9
|
|
4
|
+
data.tar.gz: f882a75e2b6c4c56b09b02419eb67b08e3d771958f5d3445f51ebbd93ffba806
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5ad0e0bbe190e4e3c908561a379513b88d134cf2fafc454d8a843b0467a90d51577f9d1d40ab553774588ce23c454bccac19ba6608239fe5503ae2a5cf4ff4cd
|
|
7
|
+
data.tar.gz: 02f96c88f95bde1860894cb3e84d849b1a62bf35285178997ead4992ee4f9a8572ea9b48e7a5c73e0bf573cc3be56ee2dc056f2bce008792d180a286b8940813
|
|
@@ -11,7 +11,8 @@ module Glib::Params
|
|
|
11
11
|
|
|
12
12
|
# Resolve a stringly-typed request param (or any boundary string) to one
|
|
13
13
|
# symbol drawn from a closed allow-list (+allowed_symbols+), returning
|
|
14
|
-
# +default+ when the value is missing, blank, or not recognised
|
|
14
|
+
# +default+ when the value is missing, blank, or not recognised — with
|
|
15
|
+
# one default-config exception on mutating requests, spelled out below.
|
|
15
16
|
#
|
|
16
17
|
# This is the symbol-DoS-safe replacement for `params[:x].to_sym`. A bare
|
|
17
18
|
# `.to_sym` on a raw value mints a symbol for every distinct string a client
|
|
@@ -30,16 +31,23 @@ module Glib::Params
|
|
|
30
31
|
# Blank/missing values fall through to +default+ quietly on EVERY method
|
|
31
32
|
# (forms legitimately post no value; no symbol's string form is blank).
|
|
32
33
|
#
|
|
34
|
+
# +raise_on_unrecognized+ (default +true+) keeps that raise. Pass +false+
|
|
35
|
+
# for endpoints anyone can POST to — anonymous public endpoints where junk
|
|
36
|
+
# values are expected traffic: the present-but-unrecognised case then
|
|
37
|
+
# degrades to +default+ on every method instead of raising, so bot probes
|
|
38
|
+
# cannot 500 the endpoint. Endpoints whose only writers are the app's own
|
|
39
|
+
# UI keep the default — there the raise is the forgotten-entry detector.
|
|
40
|
+
#
|
|
33
41
|
# +allowed_symbols+ may also contain strings (e.g. a Rails enum's `.keys`)
|
|
34
42
|
# — the matched entry is symbolized on the way out, so the return value is
|
|
35
43
|
# ALWAYS a symbol (or +default+). That `to_sym` runs only on the
|
|
36
44
|
# developer-controlled list entry, never on +value+, so the DoS-safety
|
|
37
45
|
# above is unaffected.
|
|
38
|
-
def glib_allowlist_symbol_param(value, allowed_symbols, default:)
|
|
46
|
+
def glib_allowlist_symbol_param(value, allowed_symbols, default:, raise_on_unrecognized: true)
|
|
39
47
|
match = allowed_symbols.find { |symbol| symbol.to_s == value.to_s }&.to_sym
|
|
40
48
|
return match if match
|
|
41
49
|
|
|
42
|
-
if value.present? && !request.get? && !request.head?
|
|
50
|
+
if raise_on_unrecognized && value.present? && !request.get? && !request.head?
|
|
43
51
|
raise UnrecognizedValue,
|
|
44
52
|
"Unrecognised #{request.request_method} param value #{value.to_s.truncate(80).inspect} " \
|
|
45
53
|
"(allowed: #{allowed_symbols.map(&:to_sym).inspect})"
|
|
@@ -29,12 +29,18 @@ module Glib
|
|
|
29
29
|
if defined?(Rollbar)
|
|
30
30
|
# `GLib.log.warn` reports arrive with level=warning; everything else
|
|
31
31
|
# (uncaught errors, `GLib.log.error`) is an error. Prefixed so
|
|
32
|
-
#
|
|
32
|
+
# client-side reports are distinguishable from server exceptions;
|
|
33
33
|
# the details ride along as custom data for grouping.
|
|
34
34
|
rollbar_level = params[:level] == 'warning' ? :warning : :error
|
|
35
|
+
# The prefix names the reporting runtime: the npm client sends no
|
|
36
|
+
# platform and stays "JS"; the Android renderer sends "ANDROID"
|
|
37
|
+
# (spec: thread 174). A platform TAG, not free text -- truncated so
|
|
38
|
+
# a crafted value cannot smuggle a payload into the message, and
|
|
39
|
+
# absent/blank degrades to the historical JS label.
|
|
40
|
+
platform = params[:platform].to_s[0, 16].presence || 'JS'
|
|
35
41
|
Rollbar.public_send(
|
|
36
42
|
rollbar_level,
|
|
37
|
-
"
|
|
43
|
+
"#{platform}: #{params[:message]}",
|
|
38
44
|
stack: params[:stack],
|
|
39
45
|
url: params[:url],
|
|
40
46
|
context: params[:context],
|
|
@@ -39,10 +39,10 @@ module Glib
|
|
|
39
39
|
add_element_to_array 'action', m, *args
|
|
40
40
|
else
|
|
41
41
|
if !Rails.env.production? && @singleton_action_set
|
|
42
|
-
raise
|
|
42
|
+
raise 'Multiple actions called on a singleton ActionBuilder. ' \
|
|
43
43
|
"Only one action is allowed. Previous action: '#{@singleton_action_name}', " \
|
|
44
44
|
"current action: '#{m}'. Use `run_multiple` with `childActions` or " \
|
|
45
|
-
|
|
45
|
+
'chain actions using `onClose` callbacks.'
|
|
46
46
|
end
|
|
47
47
|
@singleton_action_set = true
|
|
48
48
|
@singleton_action_name = m
|
|
@@ -170,13 +170,6 @@ module Glib
|
|
|
170
170
|
end
|
|
171
171
|
end
|
|
172
172
|
|
|
173
|
-
module Labels
|
|
174
|
-
class Set < Action
|
|
175
|
-
string :text
|
|
176
|
-
action :onSet
|
|
177
|
-
end
|
|
178
|
-
end
|
|
179
|
-
|
|
180
173
|
module Lists
|
|
181
174
|
class Append < Action
|
|
182
175
|
hash :row
|
|
@@ -452,47 +452,6 @@ class Glib::JsonUi::ViewBuilder
|
|
|
452
452
|
end
|
|
453
453
|
end
|
|
454
454
|
|
|
455
|
-
class Table2 < View
|
|
456
|
-
attr_reader :template
|
|
457
|
-
|
|
458
|
-
hash :nextPage
|
|
459
|
-
action :onScrollToTop
|
|
460
|
-
action :onScrollToBottom
|
|
461
|
-
|
|
462
|
-
def initialize(json, page)
|
|
463
|
-
super
|
|
464
|
-
@template = Glib::JsonUi::TableBuilders::Template.new(json, self)
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
def header(options = {})
|
|
468
|
-
json.header do
|
|
469
|
-
json.backgroundColor options.delete(:backgroundColor)
|
|
470
|
-
json.cellViews do
|
|
471
|
-
options.delete(:cellViews)&.call page.view_builder
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
json.colSpans options.delete(:colSpans)
|
|
475
|
-
end
|
|
476
|
-
|
|
477
|
-
raise "Invalid properties: #{options.keys}" if options.size > 0
|
|
478
|
-
end
|
|
479
|
-
|
|
480
|
-
def rows(options = {})
|
|
481
|
-
block = options.delete(:builder)
|
|
482
|
-
json.rows do
|
|
483
|
-
if (objects = options.delete(:objects))
|
|
484
|
-
objects.each_with_index do |object, index|
|
|
485
|
-
block&.call template, object, index
|
|
486
|
-
end
|
|
487
|
-
else
|
|
488
|
-
block&.call template
|
|
489
|
-
end
|
|
490
|
-
end
|
|
491
|
-
|
|
492
|
-
raise "Invalid properties: #{options.keys}" if options.size > 0
|
|
493
|
-
end
|
|
494
|
-
end
|
|
495
|
-
|
|
496
455
|
# The generic bulk-edit table: form-peer submission, per-row POSTs,
|
|
497
456
|
# viewCells/viewHeaders, plus the full parse/gate/dedup config so any
|
|
498
457
|
# consumer can compose specialized import behavior (it replaced the
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
json.title 'Test Page (Bottom Banners)'
|
|
2
|
+
|
|
3
|
+
page = json_ui_page json
|
|
4
|
+
|
|
5
|
+
render 'json_ui/garage/test_page/header', json: json, page: page
|
|
6
|
+
|
|
7
|
+
page.body(
|
|
8
|
+
childViews: ->(body) do
|
|
9
|
+
body.panels_responsive(
|
|
10
|
+
padding: glib_json_padding_body,
|
|
11
|
+
childViews: ->(res) do
|
|
12
|
+
res.h2 text: 'Bottom Banners'
|
|
13
|
+
res.spacer height: 8
|
|
14
|
+
res.button text: "bottomBanners/open targetId: 'dock1'", onClick: ->(action) do
|
|
15
|
+
action.bottomBanners_open targetId: 'dock1', newView: ->(view) do
|
|
16
|
+
view.panels_responsive(
|
|
17
|
+
styleClass: ['frameless'],
|
|
18
|
+
childViews: ->(panel) do
|
|
19
|
+
panel.label text: 'Upload in progress'
|
|
20
|
+
panel.spacer height: 4
|
|
21
|
+
panel.button text: 'Details', onClick: ->(subaction) do
|
|
22
|
+
subaction.dialogs_alert message: 'Upload details'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
res.spacer height: 4
|
|
29
|
+
res.button text: "bottomBanners/open targetId: 'dock2'", onClick: ->(action) do
|
|
30
|
+
action.bottomBanners_open targetId: 'dock2', newView: ->(view) do
|
|
31
|
+
view.panels_responsive(
|
|
32
|
+
styleClass: ['frameless'],
|
|
33
|
+
childViews: ->(panel) do
|
|
34
|
+
panel.banners_alert title: 'Background task', message: 'A long-running task is still active.'
|
|
35
|
+
end
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
res.spacer height: 4
|
|
40
|
+
res.button text: "bottomBanners/open replace 'dock1'", onClick: ->(action) do
|
|
41
|
+
action.bottomBanners_open targetId: 'dock1', newView: ->(view) do
|
|
42
|
+
view.panels_responsive(
|
|
43
|
+
styleClass: ['frameless'],
|
|
44
|
+
childViews: ->(panel) do
|
|
45
|
+
panel.label text: 'Upload complete'
|
|
46
|
+
panel.spacer height: 4
|
|
47
|
+
panel.button text: 'Dismiss', onClick: ->(subaction) do
|
|
48
|
+
subaction.bottomBanners_close targetId: 'dock1'
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
res.spacer height: 4
|
|
55
|
+
res.button text: "bottomBanners/close targetId: 'dock1'", onClick: ->(action) do
|
|
56
|
+
action.bottomBanners_close targetId: 'dock1'
|
|
57
|
+
end
|
|
58
|
+
res.spacer height: 4
|
|
59
|
+
res.button text: "bottomBanners/close targetId: 'dock2'", onClick: ->(action) do
|
|
60
|
+
action.bottomBanners_close targetId: 'dock2'
|
|
61
|
+
end
|
|
62
|
+
res.spacer height: 4
|
|
63
|
+
res.button text: 'bottomBanners/close (no targetId)', onClick: ->(action) do
|
|
64
|
+
action.bottomBanners_close
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
)
|
|
@@ -10,15 +10,20 @@ page.body childViews: ->(body) do
|
|
|
10
10
|
res.h2 text: 'Overview'
|
|
11
11
|
res.p text: 'Web panels embed external web content within a panel container.'
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
# Hermetic content on the serving host itself (spec 169, Decision 5):
|
|
14
|
+
# the recording host's public/ carries the two deterministic pages, so
|
|
15
|
+
# the emitted URLs bake an origin the cassette replay can rewrite and
|
|
16
|
+
# serve — an external URL would leave the emulator for the real network
|
|
17
|
+
# and no golden could depend on it.
|
|
18
|
+
url_content = "#{request.base_url}/g-web-panel.html"
|
|
19
|
+
url_alt = "#{request.base_url}/g-web-panel-alt.html"
|
|
15
20
|
|
|
16
21
|
res.spacer height: 12
|
|
17
22
|
res.hr width: 'matchParent'
|
|
18
23
|
|
|
19
24
|
res.h2 text: 'Basic'
|
|
20
25
|
res.spacer height: 8
|
|
21
|
-
res.panels_web id: 'web_main', width: 'matchParent', height: 300, url:
|
|
26
|
+
res.panels_web id: 'web_main', width: 'matchParent', height: 300, url: url_content
|
|
22
27
|
|
|
23
28
|
res.spacer height: 12
|
|
24
29
|
res.hr width: 'matchParent'
|
|
@@ -26,11 +31,11 @@ page.body childViews: ->(body) do
|
|
|
26
31
|
res.h2 text: 'Variants and Props'
|
|
27
32
|
res.spacer height: 8
|
|
28
33
|
res.panels_flow innerPadding: { bottom: 0 }, childViews: ->(flow) do
|
|
29
|
-
flow.button text: '
|
|
30
|
-
action.logics_set targetId: 'web_main', data: { url:
|
|
34
|
+
flow.button text: 'Content A', onClick: ->(action) do
|
|
35
|
+
action.logics_set targetId: 'web_main', data: { url: url_content }
|
|
31
36
|
end
|
|
32
37
|
flow.spacer width: 4
|
|
33
|
-
flow.button text: '
|
|
38
|
+
flow.button text: 'Content B', onClick: ->(action) do
|
|
34
39
|
action.logics_set targetId: 'web_main', data: { url: url_alt }
|
|
35
40
|
end
|
|
36
41
|
flow.spacer width: 4
|
|
@@ -60,6 +65,6 @@ page.body childViews: ->(body) do
|
|
|
60
65
|
res.h2 text: 'Edge and Advanced'
|
|
61
66
|
res.spacer height: 8
|
|
62
67
|
res.label text: 'Small viewport'
|
|
63
|
-
res.panels_web width: 'matchParent', height: 120, url:
|
|
68
|
+
res.panels_web width: 'matchParent', height: 120, url: url_content
|
|
64
69
|
end
|
|
65
70
|
end
|
|
@@ -14,12 +14,6 @@ json_ui_page json do |page|
|
|
|
14
14
|
# ul.label text: 'Label'
|
|
15
15
|
# end
|
|
16
16
|
|
|
17
|
-
scroll.spacer height: 20
|
|
18
|
-
scroll.h2 text: 'Time'
|
|
19
|
-
scroll.spacer height: 6
|
|
20
|
-
scroll.datetime value: 1.week.ago, format: 'YYYY-MM-DD'
|
|
21
|
-
scroll.datetime value: DateTime.current, format: 'hh:mm:ss', tick: true
|
|
22
|
-
|
|
23
17
|
# scroll.spacer height: 20
|
|
24
18
|
# scroll.h2 text: 'Map'
|
|
25
19
|
# scroll.spacer height: 6
|
|
@@ -30,5 +24,15 @@ json_ui_page json do |page|
|
|
|
30
24
|
scroll.spacer height: 6
|
|
31
25
|
scroll.calendar width: 'matchParent', height: 500, dataUrl: json_ui_garage_url(path: 'views/calendar_data')
|
|
32
26
|
|
|
27
|
+
# h5/h6 exercised here rather than views/texts: the texts page is pinned
|
|
28
|
+
# by the client suite's golden, and a non-corpus page covers the headings
|
|
29
|
+
# without shifting it (component inventory, thread 195).
|
|
30
|
+
scroll.spacer height: 20
|
|
31
|
+
scroll.h2 text: 'Sub-headings'
|
|
32
|
+
scroll.spacer height: 6
|
|
33
|
+
scroll.h5 text: 'Heading 5'
|
|
34
|
+
scroll.spacer height: 6
|
|
35
|
+
scroll.h6 text: 'Heading 6'
|
|
36
|
+
|
|
33
37
|
end
|
|
34
38
|
end
|
data/lib/glib/json_ui/config.rb
CHANGED
|
@@ -3,22 +3,21 @@ module Glib
|
|
|
3
3
|
# Global JSON UI settings.
|
|
4
4
|
#
|
|
5
5
|
# `name_separator` controls the character that joins the namespace and the
|
|
6
|
-
# component/action name in the generated JSON, e.g. `
|
|
7
|
-
# (default) vs `
|
|
6
|
+
# component/action name in the generated JSON, e.g. `panels_responsive`
|
|
7
|
+
# (default since 7.0) vs `panels/responsive`.
|
|
8
8
|
#
|
|
9
|
-
#
|
|
10
|
-
# in the next major version. Apps opt in early via an initializer:
|
|
9
|
+
# Apps that need the legacy slash names opt back in via an initializer:
|
|
11
10
|
#
|
|
12
11
|
# # config/initializers/glib.rb
|
|
13
|
-
# Glib::JsonUi::Config.name_separator = '
|
|
12
|
+
# Glib::JsonUi::Config.name_separator = '/'
|
|
14
13
|
#
|
|
15
|
-
# Frontends built on glib-web-npm accept either form, so
|
|
16
|
-
# server-side-only
|
|
14
|
+
# Frontends built on glib-web-npm accept either form, so this is a
|
|
15
|
+
# server-side-only setting.
|
|
17
16
|
class Config
|
|
18
17
|
SEPARATORS = ['/', '_'].freeze
|
|
19
18
|
|
|
20
|
-
# The shipped default
|
|
21
|
-
#
|
|
19
|
+
# The shipped default since the 7.0 major version. Apps that need the
|
|
20
|
+
# legacy names opt back in via `Config.name_separator = '/'`.
|
|
22
21
|
DEFAULT_NAME_SEPARATOR = '_'
|
|
23
22
|
|
|
24
23
|
@@name_separator = DEFAULT_NAME_SEPARATOR
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: glib-web
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 7.0
|
|
4
|
+
version: 7.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ''
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-10-12 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: activestorage
|
|
@@ -191,6 +192,7 @@ dependencies:
|
|
|
191
192
|
- - ">="
|
|
192
193
|
- !ruby/object:Gem::Version
|
|
193
194
|
version: '0'
|
|
195
|
+
description:
|
|
194
196
|
email: ''
|
|
195
197
|
executables: []
|
|
196
198
|
extensions: []
|
|
@@ -234,7 +236,6 @@ files:
|
|
|
234
236
|
- app/helpers/glib/json_ui/action_builder/dialogs.rb
|
|
235
237
|
- app/helpers/glib/json_ui/action_builder/fields.rb
|
|
236
238
|
- app/helpers/glib/json_ui/action_builder/files.rb
|
|
237
|
-
- app/helpers/glib/json_ui/action_builder/global_states.rb
|
|
238
239
|
- app/helpers/glib/json_ui/action_builder/http.rb
|
|
239
240
|
- app/helpers/glib/json_ui/action_builder/iap.rb
|
|
240
241
|
- app/helpers/glib/json_ui/action_builder/logics.rb
|
|
@@ -438,6 +439,7 @@ files:
|
|
|
438
439
|
- app/views/json_ui/garage/test_page/_header.json.jbuilder
|
|
439
440
|
- app/views/json_ui/garage/test_page/auth.json.jbuilder
|
|
440
441
|
- app/views/json_ui/garage/test_page/auto_validate.json.jbuilder
|
|
442
|
+
- app/views/json_ui/garage/test_page/bottom_banners.json.jbuilder
|
|
441
443
|
- app/views/json_ui/garage/test_page/browsers.json.jbuilder
|
|
442
444
|
- app/views/json_ui/garage/test_page/calendar.json.jbuilder
|
|
443
445
|
- app/views/json_ui/garage/test_page/calendar_empty_data.json.jbuilder
|
|
@@ -604,8 +606,10 @@ files:
|
|
|
604
606
|
- lib/glib/time_returning_mailer.rb
|
|
605
607
|
- lib/glib/value.rb
|
|
606
608
|
- lib/tasks/db.rake
|
|
609
|
+
homepage:
|
|
607
610
|
licenses: []
|
|
608
611
|
metadata: {}
|
|
612
|
+
post_install_message:
|
|
609
613
|
rdoc_options: []
|
|
610
614
|
require_paths:
|
|
611
615
|
- lib
|
|
@@ -620,7 +624,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
620
624
|
- !ruby/object:Gem::Version
|
|
621
625
|
version: '0'
|
|
622
626
|
requirements: []
|
|
623
|
-
rubygems_version: 4.
|
|
627
|
+
rubygems_version: 3.4.6
|
|
628
|
+
signing_key:
|
|
624
629
|
specification_version: 4
|
|
625
630
|
summary: ''
|
|
626
631
|
test_files: []
|