glib-web 4.42.4 → 4.43.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.
Files changed (23) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/glib/json_ui/action_builder/browsers.rb +10 -0
  3. data/app/views/json_ui/garage/forms/selects.json.jbuilder +240 -174
  4. data/app/views/json_ui/garage/tables/bulk_edit.json.jbuilder +0 -24
  5. data/app/views/json_ui/garage/test_page/_header.json.jbuilder +25 -15
  6. data/app/views/json_ui/garage/test_page/auth.json.jbuilder +113 -0
  7. data/app/views/json_ui/garage/test_page/browsers.json.jbuilder +44 -0
  8. data/app/views/json_ui/garage/test_page/commands.json.jbuilder +30 -0
  9. data/app/views/json_ui/garage/test_page/cookies.json.jbuilder +12 -4
  10. data/app/views/json_ui/garage/test_page/fields.json.jbuilder +160 -0
  11. data/app/views/json_ui/garage/test_page/fields_dynamicSelect.json.jbuilder +177 -0
  12. data/app/views/json_ui/garage/test_page/fields_select.json.jbuilder +152 -0
  13. data/app/views/json_ui/garage/test_page/fields_sign.json.jbuilder +153 -0
  14. data/app/views/json_ui/garage/test_page/fields_timer.json.jbuilder +148 -0
  15. data/app/views/json_ui/garage/test_page/fields_upload.json.jbuilder +129 -0
  16. data/app/views/json_ui/garage/test_page/forms.json.jbuilder +6 -2
  17. data/app/views/json_ui/garage/test_page/list.json.jbuilder +110 -69
  18. data/app/views/json_ui/garage/test_page/panels_bulkEdit2.json.jbuilder +240 -0
  19. data/app/views/json_ui/garage/test_page/popovers.json.jbuilder +6 -2
  20. data/app/views/json_ui/garage/test_page/progressCircle.json.jbuilder +74 -65
  21. data/app/views/json_ui/garage/test_page/table.json.jbuilder +157 -88
  22. metadata +9 -2
  23. data/app/views/json_ui/garage/test_page/file_upload_new.json.jbuilder +0 -158
@@ -0,0 +1,113 @@
1
+ json.title 'Test Page (Auth)'
2
+
3
+ page = json_ui_page json
4
+
5
+ page.body(
6
+ childViews: ->(body) do
7
+ render 'json_ui/garage/test_page/header', view: body
8
+ body.panels_responsive(
9
+ padding: glib_json_padding_body,
10
+ childViews: ->(res) do
11
+ res.h2 text: 'Auth'
12
+ res.label text: 'Actions for preparing auth state before HTTP requests.'
13
+ res.spacer height: 12
14
+ res.hr width: 'matchParent'
15
+ res.spacer height: 12
16
+
17
+ res.h2 text: 'Overview'
18
+ res.label text: 'Use auth_saveCsrfToken to store CSRF tokens for later HTTP actions.'
19
+ res.spacer height: 12
20
+ res.hr width: 'matchParent'
21
+ res.spacer height: 12
22
+
23
+ res.h2 text: 'Basic example'
24
+ res.spacer height: 8
25
+ res.button(
26
+ text: 'auth/saveCsrfToken',
27
+ onClick: ->(action) do
28
+ action.auth_saveCsrfToken token: form_authenticity_token
29
+ end
30
+ )
31
+
32
+ res.spacer height: 16
33
+ res.hr width: 'matchParent'
34
+ res.spacer height: 16
35
+
36
+ res.h2 text: 'Variants/props'
37
+ res.spacer height: 8
38
+ res.panels_flow(
39
+ innerPadding: { bottom: 0 },
40
+ width: 'matchParent',
41
+ childViews: ->(flow) do
42
+ flow.button(
43
+ text: 'auth/saveCsrfToken (with callback)',
44
+ onClick: ->(action) do
45
+ action.auth_saveCsrfToken(
46
+ token: form_authenticity_token,
47
+ onSave: ->(subaction) do
48
+ subaction.snackbars_alert message: 'Token saved', styleClass: 'success'
49
+ end
50
+ )
51
+ end
52
+ )
53
+ flow.spacer width: 8
54
+ flow.button(
55
+ text: 'auth/saveCsrfToken (manual token)',
56
+ onClick: ->(action) do
57
+ action.auth_saveCsrfToken token: "manual_#{SecureRandom.hex(4)}"
58
+ end
59
+ )
60
+ end
61
+ )
62
+
63
+ res.spacer height: 16
64
+ res.hr width: 'matchParent'
65
+ res.spacer height: 16
66
+
67
+ res.h2 text: 'Actions/events'
68
+ res.spacer height: 8
69
+ res.label id: 'auth_status', text: 'Status: idle'
70
+ res.spacer height: 8
71
+ res.button(
72
+ text: 'auth/saveCsrfToken (onSave)',
73
+ onClick: ->(action) do
74
+ action.auth_saveCsrfToken(
75
+ token: form_authenticity_token,
76
+ onSave: ->(subaction) do
77
+ subaction.runMultiple(
78
+ childActions: ->(multi) do
79
+ multi.logics_set targetId: 'auth_status', data: { text: 'Status: token saved' }
80
+ multi.snackbars_alert message: 'Saved', styleClass: 'success'
81
+ end
82
+ )
83
+ end
84
+ )
85
+ end
86
+ )
87
+
88
+ res.spacer height: 16
89
+ res.hr width: 'matchParent'
90
+ res.spacer height: 16
91
+
92
+ res.h2 text: 'Edge/advanced'
93
+ res.spacer height: 8
94
+ res.button(
95
+ text: 'auth/saveCsrfToken + http/post',
96
+ onClick: ->(action) do
97
+ action.auth_saveCsrfToken(
98
+ token: form_authenticity_token,
99
+ onSave: ->(subaction) do
100
+ subaction.http_post(
101
+ url: json_ui_garage_url(path: 'forms/basic_post'),
102
+ formData: {
103
+ user: { name: { first: 'Auth', last: 'Post' } }
104
+ }
105
+ )
106
+ end
107
+ )
108
+ end
109
+ )
110
+ end
111
+ )
112
+ end
113
+ )
@@ -83,6 +83,50 @@ page.body(
83
83
  res.hr width: 'matchParent'
84
84
  res.spacer height: 16
85
85
 
86
+ res.h2 text: 'Set location'
87
+ res.spacer height: 8
88
+ res.label id: 'browsers_location_status', text: 'Location: idle'
89
+ res.spacer height: 8
90
+ res.button(
91
+ text: 'browsers/setLocation (onSet)',
92
+ onClick: ->(action) do
93
+ action.browsers_setLocation(
94
+ url: json_ui_garage_url(path: 'forms/generic_post_all'),
95
+ onSet: ->(set) do
96
+ set.runMultiple(
97
+ childActions: ->(multi) do
98
+ multi.logics_set targetId: 'browsers_location_status', data: { text: 'Location: set' }
99
+ multi.snackbars_alert message: 'Location set'
100
+ end
101
+ )
102
+ end
103
+ )
104
+ end
105
+ )
106
+ res.spacer height: 8
107
+ res.button(
108
+ text: 'browsers/setLocation (replace: false)',
109
+ onClick: ->(action) do
110
+ action.browsers_setLocation(
111
+ url: json_ui_garage_url(path: 'forms/generic_post_all'),
112
+ replace: false,
113
+ onSet: ->(set) do
114
+ set.runMultiple(
115
+ childActions: ->(multi) do
116
+ multi.logics_set targetId: 'browsers_location_status',
117
+ data: { text: 'Location: set (replace: false)' }
118
+ multi.snackbars_alert message: 'Location set (replace: false)'
119
+ end
120
+ )
121
+ end
122
+ )
123
+ end
124
+ )
125
+
126
+ res.spacer height: 16
127
+ res.hr width: 'matchParent'
128
+ res.spacer height: 16
129
+
86
130
  res.h2 text: 'Edge/advanced'
87
131
  res.spacer height: 8
88
132
  res.button(
@@ -80,6 +80,36 @@ page.body(
80
80
  end
81
81
  )
82
82
 
83
+ res.spacer height: 8
84
+ res.button(
85
+ text: 'commands/custom (with callbacks)',
86
+ onClick: ->(action) do
87
+ action.commands_custom(
88
+ name: 'open_settings',
89
+ properties: {
90
+ source: 'commands_test_page',
91
+ payload: { mode: 'demo' }
92
+ },
93
+ onSuccess: ->(subaction) do
94
+ subaction.runMultiple(
95
+ childActions: ->(ssaction) do
96
+ ssaction.logics_set targetId: 'commands_status', data: { text: 'Status: custom success' }
97
+ ssaction.snackbars_alert message: 'Custom command succeeded', styleClass: 'success'
98
+ end
99
+ )
100
+ end,
101
+ onFailure: ->(subaction) do
102
+ subaction.runMultiple(
103
+ childActions: ->(ssaction) do
104
+ ssaction.logics_set targetId: 'commands_status', data: { text: 'Status: custom failure' }
105
+ ssaction.snackbars_alert message: 'Custom command failed', styleClass: 'danger'
106
+ end
107
+ )
108
+ end
109
+ )
110
+ end
111
+ )
112
+
83
113
  res.spacer height: 16
84
114
  res.hr width: 'matchParent'
85
115
  res.spacer height: 16
@@ -71,8 +71,12 @@ page.body(
71
71
  text: 'cookies/save (onSave)',
72
72
  onClick: ->(action) do
73
73
  action.cookies_save key: 'glib_cookie', value: "event_cookie_#{DateTime.current.to_i}", onSave: ->(subaction) do
74
- subaction.logics_set targetId: 'cookies_status', data: { text: 'Status: saved (callback)' }
75
- subaction.snackbars_alert message: 'Saved'
74
+ subaction.runMultiple(
75
+ childActions: ->(multi) do
76
+ multi.logics_set targetId: 'cookies_status', data: { text: 'Status: saved (callback)' }
77
+ multi.snackbars_alert message: 'Saved'
78
+ end
79
+ )
76
80
  end
77
81
  end
78
82
  )
@@ -81,8 +85,12 @@ page.body(
81
85
  text: 'cookies/remove (onRemove)',
82
86
  onClick: ->(action) do
83
87
  action.cookies_remove key: 'glib_cookie', onRemove: ->(subaction) do
84
- subaction.logics_set targetId: 'cookies_status', data: { text: 'Status: removed (callback)' }
85
- subaction.snackbars_alert message: 'Removed'
88
+ subaction.runMultiple(
89
+ childActions: ->(multi) do
90
+ multi.logics_set targetId: 'cookies_status', data: { text: 'Status: removed (callback)' }
91
+ multi.snackbars_alert message: 'Removed'
92
+ end
93
+ )
86
94
  end
87
95
  end
88
96
  )
@@ -0,0 +1,160 @@
1
+ json.title 'Test Page (Fields Actions)'
2
+
3
+ page = json_ui_page json
4
+
5
+ page.body(
6
+ childViews: ->(body) do
7
+ render 'json_ui/garage/test_page/header', view: body
8
+ body.panels_form(
9
+ padding: glib_json_padding_body,
10
+ childViews: ->(res) do
11
+ res.h2 text: 'Fields Actions'
12
+ res.label text: 'Focus, blur, reset, and read values from form fields.'
13
+ res.spacer height: 12
14
+ res.hr width: 'matchParent'
15
+ res.spacer height: 12
16
+
17
+ res.h2 text: 'Overview'
18
+ res.label text: 'Use fields actions to move focus, reset inputs, or capture current values.'
19
+ res.spacer height: 12
20
+ res.hr width: 'matchParent'
21
+ res.spacer height: 12
22
+
23
+ res.h2 text: 'Basic example'
24
+ res.spacer height: 8
25
+ res.panels_responsive(
26
+ width: 'matchParent',
27
+ childViews: ->(form) do
28
+ form.fields_text id: 'field_name', name: 'user[full_name]', label: 'Full name', placeholder: 'Full name', width: 'matchParent'
29
+ form.spacer height: 8
30
+ form.fields_number id: 'field_age', name: 'user[age]', label: 'Age', placeholder: 'Age', width: 'matchParent'
31
+ form.spacer height: 8
32
+ form.fields_textarea id: 'field_bio', name: 'user[bio]', label: 'Bio', placeholder: 'Bio', width: 'matchParent'
33
+ end
34
+ )
35
+ res.spacer height: 8
36
+ res.panels_flow(
37
+ innerPadding: { bottom: 0 },
38
+ width: 'matchParent',
39
+ childViews: ->(flow) do
40
+ flow.button(
41
+ text: 'fields/focus (name)',
42
+ onClick: ->(action) do
43
+ action.fields_focus targetId: 'field_name'
44
+ end
45
+ )
46
+ flow.spacer width: 8
47
+ flow.button(
48
+ text: 'fields/blur',
49
+ onClick: ->(action) do
50
+ action.fields_blur
51
+ end
52
+ )
53
+ end
54
+ )
55
+
56
+ res.spacer height: 16
57
+ res.hr width: 'matchParent'
58
+ res.spacer height: 16
59
+
60
+ res.h2 text: 'Variants/props'
61
+ res.spacer height: 8
62
+ res.panels_flow(
63
+ innerPadding: { bottom: 0 },
64
+ width: 'matchParent',
65
+ childViews: ->(flow) do
66
+ flow.button(
67
+ text: 'fields/reset (single)',
68
+ onClick: ->(action) do
69
+ action.fields_reset targetId: 'field_name'
70
+ end
71
+ )
72
+ flow.spacer width: 8
73
+ flow.button(
74
+ text: 'fields/reset (multiple)',
75
+ onClick: ->(action) do
76
+ action.fields_reset targetIds: ['field_name', 'field_age', 'field_bio']
77
+ end
78
+ )
79
+ flow.spacer width: 8
80
+ flow.button(
81
+ text: 'fields/focus (with onFocus)',
82
+ onClick: ->(action) do
83
+ action.fields_focus(
84
+ targetId: 'field_age',
85
+ onFocus: ->(subaction) do
86
+ subaction.snackbars_alert message: 'Focused age field'
87
+ end
88
+ )
89
+ end
90
+ )
91
+ end
92
+ )
93
+
94
+ res.spacer height: 16
95
+ res.hr width: 'matchParent'
96
+ res.spacer height: 16
97
+
98
+ res.h2 text: 'Actions/events'
99
+ res.spacer height: 8
100
+ res.label id: 'fields_status', text: 'Status: idle'
101
+ res.spacer height: 8
102
+ res.panels_flow(
103
+ innerPadding: { bottom: 0 },
104
+ width: 'matchParent',
105
+ childViews: ->(flow) do
106
+ flow.button(
107
+ text: 'fields/getValues',
108
+ onClick: ->(action) do
109
+ action.fields_getValues(
110
+ fieldNames: {
111
+ 'user[full_name]' => 'full_name',
112
+ 'user[age]' => 'age'
113
+ },
114
+ onGet: ->(subaction) do
115
+ subaction.runMultiple(
116
+ childActions: ->(multi) do
117
+ multi.logics_set targetId: 'fields_status', data: { text: 'Status: values requested' }
118
+ multi.snackbars_alert message: 'Values requested'
119
+ end
120
+ )
121
+ end
122
+ )
123
+ end
124
+ )
125
+ flow.spacer width: 8
126
+ flow.button(
127
+ text: 'fields/reset (onReset)',
128
+ onClick: ->(action) do
129
+ action.fields_reset(
130
+ targetIds: ['field_name', 'field_age', 'field_bio'],
131
+ onReset: ->(subaction) do
132
+ subaction.logics_set targetId: 'fields_status', data: { text: 'Status: reset' }
133
+ end
134
+ )
135
+ end
136
+ )
137
+ end
138
+ )
139
+
140
+ res.spacer height: 16
141
+ res.hr width: 'matchParent'
142
+ res.spacer height: 16
143
+
144
+ res.h2 text: 'Edge/advanced'
145
+ res.spacer height: 8
146
+ res.button(
147
+ text: 'fields/focus -> blur after delay',
148
+ onClick: ->(action) do
149
+ action.fields_focus(
150
+ targetId: 'field_bio',
151
+ onFocus: ->(subaction) do
152
+ subaction.timeouts_set interval: 800, onTimeout: ->(ssaction) { ssaction.fields_blur }
153
+ end
154
+ )
155
+ end
156
+ )
157
+ end
158
+ )
159
+ end
160
+ )
@@ -0,0 +1,177 @@
1
+ json.title 'Test Page (Fields Dynamic Select)'
2
+
3
+ page = json_ui_page json
4
+
5
+ page.body(
6
+ childViews: ->(body) do
7
+ render 'json_ui/garage/test_page/header', view: body
8
+
9
+ body.panels_responsive(
10
+ padding: glib_json_padding_body,
11
+ childViews: ->(res) do
12
+ res.panels_form(
13
+ url: json_ui_garage_url(path: 'forms/generic_post'),
14
+ method: 'post',
15
+ childViews: ->(form) do
16
+ base_selected = [
17
+ { value: 'id3', text: 'Item 3' }
18
+ ]
19
+
20
+ multi_selected = [
21
+ { value: 'id2', text: 'Item 2' },
22
+ { value: 'id5', text: 'Item 5' }
23
+ ]
24
+
25
+ form.h2 text: 'Overview'
26
+ form.label text: 'Dynamic select loads options from the server as the user types.'
27
+ form.spacer height: 12
28
+ form.hr width: 'matchParent'
29
+ form.spacer height: 12
30
+
31
+ form.h2 text: 'Basic example'
32
+ form.spacer height: 8
33
+ form.fields_dynamicSelect(
34
+ id: 'dynamic_select_main',
35
+ name: 'user[primary_language]',
36
+ width: 'matchParent',
37
+ label: 'Primary Language',
38
+ selectedOptions: base_selected,
39
+ url: json_ui_garage_url(path: 'forms/dynamic_select_data'),
40
+ placeholder: 'Start typing'
41
+ )
42
+ form.spacer height: 8
43
+ form.label id: 'dynamic_select_status', text: 'Status: ready'
44
+
45
+ form.spacer height: 12
46
+ form.hr width: 'matchParent'
47
+ form.spacer height: 12
48
+
49
+ form.h2 text: 'Variants/props'
50
+ form.label text: 'Switch between single and multiple selection.'
51
+ form.spacer height: 8
52
+ form.panels_flow(
53
+ innerPadding: { bottom: 0 },
54
+ width: 'matchParent',
55
+ childViews: ->(flow) do
56
+ flow.button(
57
+ text: 'Single select',
58
+ onClick: ->(action) do
59
+ action.components_set(
60
+ targetId: 'dynamic_select_main',
61
+ data: { multiple: nil, selectedOptions: base_selected, placeholder: 'Start typing' }
62
+ )
63
+ end
64
+ )
65
+ flow.spacer width: 8
66
+ flow.button(
67
+ text: 'Multiple select',
68
+ onClick: ->(action) do
69
+ action.components_set(
70
+ targetId: 'dynamic_select_main',
71
+ data: { multiple: true, selectedOptions: multi_selected, placeholder: 'Pick multiple' }
72
+ )
73
+ end
74
+ )
75
+ flow.spacer width: 8
76
+ flow.button(
77
+ text: 'Clear selection',
78
+ onClick: ->(action) do
79
+ action.components_set(
80
+ targetId: 'dynamic_select_main',
81
+ data: { selectedOptions: [], value: nil }
82
+ )
83
+ end
84
+ )
85
+ end
86
+ )
87
+
88
+ form.spacer height: 12
89
+ form.hr width: 'matchParent'
90
+ form.spacer height: 12
91
+
92
+ form.h2 text: 'Actions/events'
93
+ form.spacer height: 8
94
+ form.panels_flow(
95
+ innerPadding: { bottom: 0 },
96
+ width: 'matchParent',
97
+ childViews: ->(flow) do
98
+ flow.button(
99
+ text: 'Mark as required',
100
+ onClick: ->(action) do
101
+ action.runMultiple childActions: ->(multiple) do
102
+ multiple.components_set targetId: 'dynamic_select_main',
103
+ data: { validation: { required: { message: 'select at least one' } } }
104
+ multiple.logics_set targetId: 'dynamic_select_status', data: { text: 'Status: required' }
105
+ end
106
+ end
107
+ )
108
+ flow.spacer width: 8
109
+ flow.button(
110
+ text: 'Optional',
111
+ onClick: ->(action) do
112
+ action.runMultiple childActions: ->(multiple) do
113
+ multiple.components_set targetId: 'dynamic_select_main', data: { validation: nil }
114
+ multiple.logics_set targetId: 'dynamic_select_status', data: { text: 'Status: optional' }
115
+ end
116
+ end
117
+ )
118
+ flow.spacer width: 8
119
+ flow.button(
120
+ text: 'Submit form',
121
+ onClick: ->(action) do
122
+ action.runMultiple childActions: ->(multiple) do
123
+ multiple.forms_submit
124
+ multiple.logics_set targetId: 'dynamic_select_status', data: { text: 'Status: submitted' }
125
+ end
126
+ end
127
+ )
128
+ end
129
+ )
130
+
131
+ form.spacer height: 12
132
+ form.hr width: 'matchParent'
133
+ form.spacer height: 12
134
+
135
+ form.h2 text: 'Edge/advanced'
136
+ form.spacer height: 8
137
+ form.panels_flow(
138
+ innerPadding: { bottom: 0 },
139
+ width: 'matchParent',
140
+ childViews: ->(flow) do
141
+ flow.button(
142
+ text: 'Disable',
143
+ onClick: ->(action) do
144
+ action.components_set targetId: 'dynamic_select_main', data: { disabled: true }
145
+ end
146
+ )
147
+ flow.spacer width: 8
148
+ flow.button(
149
+ text: 'Enable',
150
+ onClick: ->(action) do
151
+ action.components_set targetId: 'dynamic_select_main', data: { disabled: nil }
152
+ end
153
+ )
154
+ flow.spacer width: 8
155
+ flow.button(
156
+ text: 'Restore defaults',
157
+ onClick: ->(action) do
158
+ action.components_set(
159
+ targetId: 'dynamic_select_main',
160
+ data: {
161
+ disabled: nil,
162
+ validation: nil,
163
+ multiple: nil,
164
+ placeholder: 'Start typing',
165
+ selectedOptions: base_selected
166
+ }
167
+ )
168
+ end
169
+ )
170
+ end
171
+ )
172
+ end
173
+ )
174
+ end
175
+ )
176
+ end
177
+ )