tina4ruby 3.10.41 → 3.10.44
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 +1 -1
- data/lib/tina4/ai.rb +492 -134
- data/lib/tina4/cli.rb +784 -74
- data/lib/tina4/database.rb +12 -5
- data/lib/tina4/dev_admin.rb +275 -66
- data/lib/tina4/events.rb +19 -0
- data/lib/tina4/field_types.rb +6 -1
- data/lib/tina4/frond.rb +112 -81
- data/lib/tina4/metrics.rb +55 -3
- data/lib/tina4/orm.rb +17 -7
- data/lib/tina4/public/js/tina4-dev-admin.min.js +167 -28
- data/lib/tina4/query_builder.rb +8 -2
- data/lib/tina4/rack_app.rb +25 -1
- data/lib/tina4/template.rb +57 -15
- data/lib/tina4/version.rb +1 -1
- metadata +1 -1
data/lib/tina4/rack_app.rb
CHANGED
|
@@ -132,6 +132,14 @@ module Tina4
|
|
|
132
132
|
handle_500(e, env)
|
|
133
133
|
end
|
|
134
134
|
|
|
135
|
+
# Dispatch a pre-built Request through the Rack app and return the Rack response triple.
|
|
136
|
+
# Useful for testing and embedding without starting an HTTP server.
|
|
137
|
+
def handle(request)
|
|
138
|
+
env = request.env
|
|
139
|
+
env["rack.input"].rewind if env["rack.input"].respond_to?(:rewind)
|
|
140
|
+
call(env)
|
|
141
|
+
end
|
|
142
|
+
|
|
135
143
|
private
|
|
136
144
|
|
|
137
145
|
def handle_route(env, route, path_params)
|
|
@@ -426,6 +434,8 @@ module Tina4
|
|
|
426
434
|
.view-modal-content{background:#1e293b;border:1px solid #334155;border-radius:0.75rem;padding:2rem;max-width:700px;width:90%;max-height:80vh;overflow-y:auto;position:relative}
|
|
427
435
|
.view-modal-close{position:absolute;top:0.75rem;right:1rem;color:#94a3b8;cursor:pointer;font-size:1.25rem;background:none;border:none}
|
|
428
436
|
.view-modal-close:hover{color:#e2e8f0}
|
|
437
|
+
@keyframes wiggle{0%{transform:rotate(0deg)}15%{transform:rotate(14deg)}30%{transform:rotate(-10deg)}45%{transform:rotate(8deg)}60%{transform:rotate(-4deg)}75%{transform:rotate(2deg)}100%{transform:rotate(0deg)}}
|
|
438
|
+
.star-wiggle{display:inline-block;transform-origin:center}
|
|
429
439
|
</style>
|
|
430
440
|
</head>
|
|
431
441
|
<body>
|
|
@@ -439,7 +449,7 @@ module Tina4
|
|
|
439
449
|
<a href="/__dev" class="btn">Dev Admin</a>
|
|
440
450
|
<a href="#gallery" class="btn">Gallery</a>
|
|
441
451
|
<a href="https://github.com/tina4stack/tina4-ruby" class="btn" target="_blank">GitHub</a>
|
|
442
|
-
<a href="https://github.com/tina4stack/tina4-ruby/stargazers" class="btn" target="_blank">&#
|
|
452
|
+
<a href="https://github.com/tina4stack/tina4-ruby/stargazers" class="btn" target="_blank"><span class="star-wiggle">☆</span> Star</a>
|
|
443
453
|
</div>
|
|
444
454
|
<div class="status">
|
|
445
455
|
<span><span class="dot"></span>Server running</span>
|
|
@@ -535,6 +545,20 @@ module Tina4
|
|
|
535
545
|
document.getElementById('viewModal').addEventListener('click', function(e) {
|
|
536
546
|
if (e.target === this) this.classList.remove('active');
|
|
537
547
|
});
|
|
548
|
+
(function(){
|
|
549
|
+
var star=document.querySelector('.star-wiggle');
|
|
550
|
+
if(!star)return;
|
|
551
|
+
function doWiggle(){
|
|
552
|
+
star.style.animation='wiggle 1.2s ease-in-out';
|
|
553
|
+
star.addEventListener('animationend',function onEnd(){
|
|
554
|
+
star.removeEventListener('animationend',onEnd);
|
|
555
|
+
star.style.animation='none';
|
|
556
|
+
var delay=3000+Math.random()*15000;
|
|
557
|
+
setTimeout(doWiggle,delay);
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
setTimeout(doWiggle,3000);
|
|
561
|
+
})();
|
|
538
562
|
</script>
|
|
539
563
|
</body>
|
|
540
564
|
</html>
|
data/lib/tina4/template.rb
CHANGED
|
@@ -70,13 +70,27 @@ module Tina4
|
|
|
70
70
|
msg = messages[code] || "Error"
|
|
71
71
|
colors = { 403 => "#f59e0b", 404 => "#3b82f6", 500 => "#ef4444" }
|
|
72
72
|
color = colors[code] || "#ef4444"
|
|
73
|
+
|
|
73
74
|
<<~HTML
|
|
74
75
|
<!DOCTYPE html>
|
|
75
76
|
<html lang="en">
|
|
76
|
-
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
<
|
|
77
|
+
#{error_overlay_head("#{code} — #{msg}")}
|
|
78
|
+
<body>
|
|
79
|
+
#{error_overlay_css(color)}
|
|
80
|
+
<div class="error-card">
|
|
81
|
+
<div class="logo">T4</div>
|
|
82
|
+
<div class="error-code">#{code}</div>
|
|
83
|
+
<div class="error-title">#{msg}</div>
|
|
84
|
+
<div class="error-msg">Something went wrong while processing your request.</div>
|
|
85
|
+
<a href="/" class="error-home">Go Home</a>
|
|
86
|
+
</div>
|
|
87
|
+
</body>
|
|
88
|
+
</html>
|
|
89
|
+
HTML
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def error_overlay_css(color)
|
|
93
|
+
<<~CSS
|
|
80
94
|
<style>
|
|
81
95
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
82
96
|
body { font-family: system-ui, -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
@@ -88,18 +102,46 @@ module Tina4
|
|
|
88
102
|
.error-home:hover { opacity: 0.9; }
|
|
89
103
|
.logo { font-size: 1.5rem; margin-bottom: 1rem; opacity: 0.5; }
|
|
90
104
|
</style>
|
|
105
|
+
CSS
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def error_overlay_head(title)
|
|
109
|
+
<<~HEAD
|
|
110
|
+
<head>
|
|
111
|
+
<meta charset="utf-8">
|
|
112
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
113
|
+
<title>#{title}</title>
|
|
91
114
|
</head>
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
115
|
+
HEAD
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def error_overlay_stacktrace(exception)
|
|
119
|
+
return "" unless exception.respond_to?(:backtrace) && exception.backtrace
|
|
120
|
+
lines = exception.backtrace.map { |l| "<li>#{l}</li>" }.join("\n")
|
|
121
|
+
"<ul class=\"stacktrace\">#{lines}</ul>"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def error_overlay_source(file, line)
|
|
125
|
+
return "" unless file && line && File.exist?(file)
|
|
126
|
+
lines = File.readlines(file)
|
|
127
|
+
start = [line.to_i - 4, 0].max
|
|
128
|
+
finish = [line.to_i + 3, lines.length - 1].min
|
|
129
|
+
snippet = lines[start..finish].each_with_index.map do |l, i|
|
|
130
|
+
num = start + i + 1
|
|
131
|
+
"<div class=\"source-line#{num == line.to_i ? ' highlight' : ''}\"><span class=\"line-num\">#{num}</span>#{l.chomp}</div>"
|
|
132
|
+
end.join("\n")
|
|
133
|
+
"<pre class=\"source-context\">#{snippet}</pre>"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def error_overlay_request(env)
|
|
137
|
+
return "" unless env.is_a?(Hash)
|
|
138
|
+
method = env["REQUEST_METHOD"] || "?"
|
|
139
|
+
path = env["PATH_INFO"] || "?"
|
|
140
|
+
"<div class=\"request-info\"><strong>#{method}</strong> #{path}</div>"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def error_overlay_env
|
|
144
|
+
"<div class=\"env-info\">Ruby #{RUBY_VERSION} | Tina4</div>"
|
|
103
145
|
end
|
|
104
146
|
end
|
|
105
147
|
|
data/lib/tina4/version.rb
CHANGED