ruflet_rails 0.0.6 → 0.0.8
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/README.md +152 -5
- data/lib/generators/ruflet/form/form_generator.rb +55 -0
- data/lib/generators/ruflet/install/install_generator.rb +111 -22
- data/lib/generators/ruflet/scaffold/scaffold_generator.rb +60 -0
- data/lib/ruflet/rails/desktop_launcher.rb +116 -0
- data/lib/ruflet/rails/form_helpers.rb +161 -0
- data/lib/ruflet/rails/install_support.rb +911 -133
- data/lib/ruflet/rails/protocol/endpoint.rb +21 -5
- data/lib/ruflet/rails/protocol/local_server.rb +61 -13
- data/lib/ruflet/rails/protocol/runner.rb +22 -9
- data/lib/ruflet/rails/protocol/web_socket_connection.rb +3 -118
- data/lib/ruflet/rails/protocol/wire_codec.rb +3 -217
- data/lib/ruflet/rails/railtie.rb +63 -4
- data/lib/ruflet/rails/resource_component.rb +191 -0
- data/lib/ruflet/rails/resource_view.rb +124 -0
- data/lib/ruflet/rails/session_registry.rb +94 -0
- data/lib/ruflet/rails/view.rb +57 -0
- data/lib/ruflet/rails.rb +167 -2
- data/lib/ruflet/version.rb +1 -1
- data/lib/ruflet_rails.rb +12 -3
- metadata +25 -3
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ruflet
|
|
4
|
+
module Rails
|
|
5
|
+
module FormHelpers
|
|
6
|
+
def ruflet_form_bindings(record, form_fields)
|
|
7
|
+
form_fields.to_h do |field|
|
|
8
|
+
[field[:name], ruflet_field_binding(field, record)]
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def ruflet_form_controls(bindings)
|
|
13
|
+
bindings.values.map { |binding| binding[:control] }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def ruflet_form_attributes(bindings, form_fields)
|
|
17
|
+
bindings.to_h do |name, binding|
|
|
18
|
+
field = form_fields.find { |candidate| candidate[:name] == name }
|
|
19
|
+
control = binding[:input] || binding[:control] || binding
|
|
20
|
+
[name, ruflet_control_value(control, field[:type])]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def ruflet_show_errors(record)
|
|
25
|
+
ruflet_show_snackbar(ruflet_error_message(record))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def ruflet_show_snackbar(message)
|
|
29
|
+
page.snackbar = snackbar(text(message), open: true)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def ruflet_field_binding(field, record)
|
|
35
|
+
type = field[:type].to_s
|
|
36
|
+
return ruflet_picker_field_binding(field, record) if %w[date datetime timestamp time].include?(type)
|
|
37
|
+
|
|
38
|
+
control = ruflet_field_control(field, record)
|
|
39
|
+
{ control: control, input: control }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def ruflet_field_control(field, record)
|
|
43
|
+
name = field[:name]
|
|
44
|
+
type = field[:type].to_s
|
|
45
|
+
value = record.public_send(name)
|
|
46
|
+
label = name.humanize
|
|
47
|
+
|
|
48
|
+
case type
|
|
49
|
+
when "association", "references", "belongs_to"
|
|
50
|
+
dropdown(
|
|
51
|
+
ruflet_association_options(field),
|
|
52
|
+
value: value.to_s,
|
|
53
|
+
label: label
|
|
54
|
+
)
|
|
55
|
+
when "boolean"
|
|
56
|
+
checkbox(label: label, value: !!value)
|
|
57
|
+
when "integer", "float", "decimal"
|
|
58
|
+
text_field(value: value.to_s, label: label, keyboard_type: "number")
|
|
59
|
+
when "text"
|
|
60
|
+
text_field(value: value.to_s, label: label, multiline: true, min_lines: 3)
|
|
61
|
+
else
|
|
62
|
+
text_field(value: value.to_s, label: label)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def ruflet_picker_field_binding(field, record)
|
|
67
|
+
name = field[:name]
|
|
68
|
+
type = field[:type].to_s
|
|
69
|
+
value = record.public_send(name)
|
|
70
|
+
label = name.humanize
|
|
71
|
+
picker = ruflet_picker_control(type, value, label)
|
|
72
|
+
display = text(ruflet_picker_display_text(label, picker.props["value"]))
|
|
73
|
+
|
|
74
|
+
picker.on(:change) do |_event|
|
|
75
|
+
page.update(picker, open: false)
|
|
76
|
+
page.close_dialog(picker)
|
|
77
|
+
page.update(display, value: ruflet_picker_display_text(label, picker.props["value"]))
|
|
78
|
+
end
|
|
79
|
+
picker.on(:dismiss) do |_event|
|
|
80
|
+
page.update(picker, open: false)
|
|
81
|
+
page.close_dialog(picker)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
{
|
|
85
|
+
control: column(
|
|
86
|
+
spacing: 6,
|
|
87
|
+
children: [
|
|
88
|
+
display,
|
|
89
|
+
outlined_button(
|
|
90
|
+
content: text("Choose #{label}"),
|
|
91
|
+
on_click: ->(_e) { page.show_dialog(picker) }
|
|
92
|
+
)
|
|
93
|
+
]
|
|
94
|
+
),
|
|
95
|
+
input: picker
|
|
96
|
+
}
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def ruflet_picker_control(type, value, label)
|
|
100
|
+
case type
|
|
101
|
+
when "time"
|
|
102
|
+
time_picker(value: value.respond_to?(:strftime) ? value.strftime("%H:%M") : value.to_s, help_text: label, open: false)
|
|
103
|
+
when "datetime", "timestamp"
|
|
104
|
+
date_picker(value: ruflet_date_value(value), help_text: label, open: false)
|
|
105
|
+
else
|
|
106
|
+
date_picker(value: ruflet_date_value(value), help_text: label, open: false)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def ruflet_control_value(control, type)
|
|
111
|
+
value = control.props["value"]
|
|
112
|
+
return nil if value.to_s.empty?
|
|
113
|
+
return value if type.to_s == "boolean"
|
|
114
|
+
return value if %w[association references belongs_to].include?(type.to_s)
|
|
115
|
+
return value.to_s.split("T", 2).first if type.to_s == "date"
|
|
116
|
+
return value.to_s if %w[datetime timestamp time].include?(type.to_s)
|
|
117
|
+
|
|
118
|
+
value.to_s
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def ruflet_association_options(field)
|
|
122
|
+
model = ruflet_association_model(field)
|
|
123
|
+
return [] unless model.respond_to?(:all)
|
|
124
|
+
|
|
125
|
+
model.all.map do |record|
|
|
126
|
+
dropdown_option(record.id.to_s, text: ruflet_association_label(record))
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def ruflet_association_model(field)
|
|
131
|
+
class_name = field[:class_name] || field[:name].to_s.sub(/_id\z/, "").camelize
|
|
132
|
+
class_name.safe_constantize if class_name.respond_to?(:safe_constantize)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def ruflet_association_label(record)
|
|
136
|
+
return record.name.to_s if record.respond_to?(:name)
|
|
137
|
+
return record.title.to_s if record.respond_to?(:title)
|
|
138
|
+
|
|
139
|
+
record.to_s
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def ruflet_date_value(value)
|
|
143
|
+
return nil if value.nil?
|
|
144
|
+
return value.iso8601 if value.respond_to?(:iso8601)
|
|
145
|
+
return value.to_date.iso8601 if value.respond_to?(:to_date)
|
|
146
|
+
|
|
147
|
+
value.to_s
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def ruflet_picker_display_text(label, value)
|
|
151
|
+
visible = value.to_s.empty? ? "Not selected" : value.to_s.split("T", 2).first
|
|
152
|
+
"#{label}: #{visible}"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def ruflet_error_message(record)
|
|
156
|
+
messages = record.errors.full_messages
|
|
157
|
+
messages.respond_to?(:to_sentence) ? messages.to_sentence : messages.join(", ")
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|