tina4ruby 0.5.1 → 3.0.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/CHANGELOG.md +1 -1
- data/README.md +360 -559
- data/exe/{tina4 → tina4ruby} +1 -0
- data/lib/tina4/ai.rb +312 -0
- data/lib/tina4/auth.rb +44 -3
- data/lib/tina4/auto_crud.rb +163 -0
- data/lib/tina4/cli.rb +242 -77
- data/lib/tina4/constants.rb +46 -0
- data/lib/tina4/container.rb +54 -0
- data/lib/tina4/cors.rb +74 -0
- data/lib/tina4/database/sqlite3_adapter.rb +139 -0
- data/lib/tina4/database.rb +43 -7
- data/lib/tina4/debug.rb +4 -79
- data/lib/tina4/dev_admin.rb +1162 -0
- data/lib/tina4/dev_mailbox.rb +191 -0
- data/lib/tina4/dev_reload.rb +9 -9
- data/lib/tina4/drivers/firebird_driver.rb +19 -3
- data/lib/tina4/drivers/mssql_driver.rb +3 -3
- data/lib/tina4/drivers/mysql_driver.rb +4 -4
- data/lib/tina4/drivers/postgres_driver.rb +9 -2
- data/lib/tina4/drivers/sqlite_driver.rb +1 -1
- data/lib/tina4/env.rb +42 -2
- data/lib/tina4/error_overlay.rb +252 -0
- data/lib/tina4/events.rb +90 -0
- data/lib/tina4/field_types.rb +4 -0
- data/lib/tina4/frond.rb +1336 -0
- data/lib/tina4/gallery/auth/meta.json +1 -0
- data/lib/tina4/gallery/auth/src/routes/api/gallery_auth.rb +114 -0
- data/lib/tina4/gallery/database/meta.json +1 -0
- data/lib/tina4/gallery/database/src/routes/api/gallery_db.rb +43 -0
- data/lib/tina4/gallery/error-overlay/meta.json +1 -0
- data/lib/tina4/gallery/error-overlay/src/routes/api/gallery_crash.rb +17 -0
- data/lib/tina4/gallery/orm/meta.json +1 -0
- data/lib/tina4/gallery/orm/src/routes/api/gallery_products.rb +16 -0
- data/lib/tina4/gallery/queue/meta.json +1 -0
- data/lib/tina4/gallery/queue/src/routes/api/gallery_queue.rb +27 -0
- data/lib/tina4/gallery/rest-api/meta.json +1 -0
- data/lib/tina4/gallery/rest-api/src/routes/api/gallery_hello.rb +14 -0
- data/lib/tina4/gallery/templates/meta.json +1 -0
- data/lib/tina4/gallery/templates/src/routes/gallery_page.rb +12 -0
- data/lib/tina4/gallery/templates/src/templates/gallery_page.twig +257 -0
- data/lib/tina4/health.rb +39 -0
- data/lib/tina4/html_element.rb +148 -0
- data/lib/tina4/localization.rb +2 -2
- data/lib/tina4/log.rb +203 -0
- data/lib/tina4/messenger.rb +484 -0
- data/lib/tina4/migration.rb +132 -29
- data/lib/tina4/orm.rb +337 -31
- data/lib/tina4/public/css/tina4.css +178 -1
- data/lib/tina4/public/css/tina4.min.css +1 -2
- data/lib/tina4/public/favicon.ico +0 -0
- data/lib/tina4/public/images/logo.svg +5 -0
- data/lib/tina4/public/images/tina4-logo-icon.webp +0 -0
- data/lib/tina4/public/js/frond.min.js +420 -0
- data/lib/tina4/public/js/tina4-dev-admin.min.js +367 -0
- data/lib/tina4/public/js/tina4.min.js +93 -0
- data/lib/tina4/public/swagger/index.html +90 -0
- data/lib/tina4/public/swagger/oauth2-redirect.html +63 -0
- data/lib/tina4/queue.rb +40 -4
- data/lib/tina4/queue_backends/lite_backend.rb +88 -0
- data/lib/tina4/rack_app.rb +314 -23
- data/lib/tina4/rate_limiter.rb +123 -0
- data/lib/tina4/request.rb +61 -15
- data/lib/tina4/response.rb +54 -24
- data/lib/tina4/response_cache.rb +134 -0
- data/lib/tina4/router.rb +90 -15
- data/lib/tina4/scss_compiler.rb +2 -2
- data/lib/tina4/seeder.rb +56 -61
- data/lib/tina4/service_runner.rb +303 -0
- data/lib/tina4/session.rb +85 -0
- data/lib/tina4/session_handlers/mongo_handler.rb +1 -1
- data/lib/tina4/session_handlers/valkey_handler.rb +43 -0
- data/lib/tina4/shutdown.rb +84 -0
- data/lib/tina4/sql_translation.rb +295 -0
- data/lib/tina4/template.rb +36 -6
- data/lib/tina4/templates/base.twig +2 -2
- data/lib/tina4/templates/errors/302.twig +14 -0
- data/lib/tina4/templates/errors/401.twig +9 -0
- data/lib/tina4/templates/errors/403.twig +22 -15
- data/lib/tina4/templates/errors/404.twig +22 -15
- data/lib/tina4/templates/errors/500.twig +31 -15
- data/lib/tina4/templates/errors/502.twig +9 -0
- data/lib/tina4/templates/errors/503.twig +12 -0
- data/lib/tina4/templates/errors/base.twig +37 -0
- data/lib/tina4/version.rb +1 -1
- data/lib/tina4/webserver.rb +28 -18
- data/lib/tina4.rb +67 -21
- metadata +52 -19
- data/lib/tina4/public/js/tina4.js +0 -134
- data/lib/tina4/public/js/tina4helper.js +0 -387
data/lib/tina4/webserver.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Tina4
|
|
4
4
|
class WebServer
|
|
5
|
-
def initialize(app, host: "0.0.0.0", port:
|
|
5
|
+
def initialize(app, host: "0.0.0.0", port: 7147)
|
|
6
6
|
@app = app
|
|
7
7
|
@host = host
|
|
8
8
|
@port = port
|
|
@@ -11,8 +11,8 @@ module Tina4
|
|
|
11
11
|
def start
|
|
12
12
|
require "webrick"
|
|
13
13
|
require "stringio"
|
|
14
|
-
Tina4.print_banner
|
|
15
|
-
Tina4::
|
|
14
|
+
Tina4.print_banner(host: @host, port: @port)
|
|
15
|
+
Tina4::Log.info("Starting Tina4 WEBrick server on http://#{@host}:#{@port}")
|
|
16
16
|
@server = WEBrick::HTTPServer.new(
|
|
17
17
|
BindAddress: @host,
|
|
18
18
|
Port: @port,
|
|
@@ -20,6 +20,9 @@ module Tina4
|
|
|
20
20
|
AccessLog: []
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
+
# Setup graceful shutdown with WEBrick server reference
|
|
24
|
+
Tina4::Shutdown.setup(server: @server)
|
|
25
|
+
|
|
23
26
|
# Use a custom servlet that passes ALL methods (including OPTIONS) to Rack
|
|
24
27
|
rack_app = @app
|
|
25
28
|
servlet = Class.new(WEBrick::HTTPServlet::AbstractServlet) do
|
|
@@ -35,21 +38,31 @@ module Tina4
|
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
define_method(:handle_request) do |webrick_req, webrick_res|
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
# Reject new requests during shutdown
|
|
42
|
+
if Tina4::Shutdown.shutting_down?
|
|
43
|
+
webrick_res.status = 503
|
|
44
|
+
webrick_res.body = '{"error":"Service shutting down"}'
|
|
45
|
+
webrick_res["content-type"] = "application/json"
|
|
46
|
+
return
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
Tina4::Shutdown.track_request do
|
|
50
|
+
env = build_rack_env(webrick_req)
|
|
51
|
+
status, headers, body = @app.call(env)
|
|
40
52
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
webrick_res.status = status
|
|
54
|
+
headers.each do |key, value|
|
|
55
|
+
if key.downcase == "set-cookie"
|
|
56
|
+
Array(value.split("\n")).each { |c| webrick_res.cookies << WEBrick::Cookie.parse_set_cookie(c) }
|
|
57
|
+
else
|
|
58
|
+
webrick_res[key] = value
|
|
59
|
+
end
|
|
47
60
|
end
|
|
48
|
-
end
|
|
49
61
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
response_body = ""
|
|
63
|
+
body.each { |chunk| response_body += chunk }
|
|
64
|
+
webrick_res.body = response_body
|
|
65
|
+
end
|
|
53
66
|
end
|
|
54
67
|
|
|
55
68
|
define_method(:build_rack_env) do |req|
|
|
@@ -88,9 +101,6 @@ module Tina4
|
|
|
88
101
|
servlet.define_method(:webrick_req_port) { port }
|
|
89
102
|
|
|
90
103
|
@server.mount("/", servlet, rack_app)
|
|
91
|
-
|
|
92
|
-
trap("INT") { @server.shutdown }
|
|
93
|
-
trap("TERM") { @server.shutdown }
|
|
94
104
|
@server.start
|
|
95
105
|
end
|
|
96
106
|
|
data/lib/tina4.rb
CHANGED
|
@@ -10,7 +10,9 @@ end
|
|
|
10
10
|
|
|
11
11
|
# ── Core (always loaded) ──────────────────────────────────────────────
|
|
12
12
|
require_relative "tina4/version"
|
|
13
|
-
require_relative "tina4/
|
|
13
|
+
require_relative "tina4/constants"
|
|
14
|
+
require_relative "tina4/log"
|
|
15
|
+
require_relative "tina4/debug" # backward compat alias
|
|
14
16
|
require_relative "tina4/env"
|
|
15
17
|
require_relative "tina4/router"
|
|
16
18
|
require_relative "tina4/request"
|
|
@@ -21,12 +23,30 @@ require_relative "tina4/database_result"
|
|
|
21
23
|
require_relative "tina4/field_types"
|
|
22
24
|
require_relative "tina4/orm"
|
|
23
25
|
require_relative "tina4/migration"
|
|
26
|
+
require_relative "tina4/auto_crud"
|
|
27
|
+
require_relative "tina4/database/sqlite3_adapter"
|
|
24
28
|
require_relative "tina4/template"
|
|
29
|
+
require_relative "tina4/frond"
|
|
25
30
|
require_relative "tina4/auth"
|
|
26
31
|
require_relative "tina4/session"
|
|
27
32
|
require_relative "tina4/middleware"
|
|
33
|
+
require_relative "tina4/cors"
|
|
34
|
+
require_relative "tina4/rate_limiter"
|
|
35
|
+
require_relative "tina4/health"
|
|
36
|
+
require_relative "tina4/shutdown"
|
|
28
37
|
require_relative "tina4/localization"
|
|
38
|
+
require_relative "tina4/container"
|
|
29
39
|
require_relative "tina4/queue"
|
|
40
|
+
require_relative "tina4/service_runner"
|
|
41
|
+
require_relative "tina4/events"
|
|
42
|
+
require_relative "tina4/dev_admin"
|
|
43
|
+
require_relative "tina4/messenger"
|
|
44
|
+
require_relative "tina4/dev_mailbox"
|
|
45
|
+
require_relative "tina4/ai"
|
|
46
|
+
require_relative "tina4/sql_translation"
|
|
47
|
+
require_relative "tina4/response_cache"
|
|
48
|
+
require_relative "tina4/html_element"
|
|
49
|
+
require_relative "tina4/error_overlay"
|
|
30
50
|
|
|
31
51
|
module Tina4
|
|
32
52
|
# ── Lazy-loaded: database drivers ─────────────────────────────────────
|
|
@@ -42,7 +62,8 @@ module Tina4
|
|
|
42
62
|
module SessionHandlers
|
|
43
63
|
autoload :FileHandler, File.expand_path("tina4/session_handlers/file_handler", __dir__)
|
|
44
64
|
autoload :RedisHandler, File.expand_path("tina4/session_handlers/redis_handler", __dir__)
|
|
45
|
-
autoload :MongoHandler,
|
|
65
|
+
autoload :MongoHandler, File.expand_path("tina4/session_handlers/mongo_handler", __dir__)
|
|
66
|
+
autoload :ValkeyHandler, File.expand_path("tina4/session_handlers/valkey_handler", __dir__)
|
|
46
67
|
end
|
|
47
68
|
|
|
48
69
|
# ── Lazy-loaded: queue backends ───────────────────────────────────────
|
|
@@ -72,27 +93,38 @@ module Tina4
|
|
|
72
93
|
autoload :ScssCompiler, File.expand_path("tina4/scss_compiler", __dir__)
|
|
73
94
|
autoload :DevReload, File.expand_path("tina4/dev_reload", __dir__)
|
|
74
95
|
autoload :FakeData, File.expand_path("tina4/seeder", __dir__)
|
|
75
|
-
autoload :Seeder, File.expand_path("tina4/seeder", __dir__)
|
|
76
96
|
autoload :WSDL, File.expand_path("tina4/wsdl", __dir__)
|
|
77
97
|
BANNER = <<~'BANNER'
|
|
78
98
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝
|
|
99
|
+
______ _ __ __
|
|
100
|
+
/_ __/(_)___ ____ _/ // /
|
|
101
|
+
/ / / / __ \/ __ `/ // /_
|
|
102
|
+
/ / / / / / / /_/ /__ __/
|
|
103
|
+
/_/ /_/_/ /_/\__,_/ /_/
|
|
85
104
|
BANNER
|
|
86
105
|
|
|
87
106
|
class << self
|
|
88
107
|
attr_accessor :root_dir, :database
|
|
89
108
|
|
|
90
|
-
def print_banner
|
|
91
|
-
|
|
92
|
-
|
|
109
|
+
def print_banner(host: "0.0.0.0", port: 7147)
|
|
110
|
+
is_tty = $stdout.respond_to?(:isatty) && $stdout.isatty
|
|
111
|
+
color = is_tty ? "\e[31m" : ""
|
|
112
|
+
reset = is_tty ? "\e[0m" : ""
|
|
113
|
+
|
|
114
|
+
is_debug = Tina4::Env.truthy?(ENV["TINA4_DEBUG"])
|
|
115
|
+
log_level = (ENV["TINA4_LOG_LEVEL"] || "[TINA4_LOG_ALL]").upcase
|
|
116
|
+
display = (host == "0.0.0.0" || host == "::") ? "localhost" : host
|
|
117
|
+
|
|
118
|
+
puts "#{color}#{BANNER}#{reset}"
|
|
119
|
+
puts " Tina4 Ruby v#{VERSION} — This is not a framework"
|
|
120
|
+
puts ""
|
|
121
|
+
puts " Server: http://#{display}:#{port}"
|
|
122
|
+
puts " Swagger: http://localhost:#{port}/swagger"
|
|
123
|
+
puts " Dashboard: http://localhost:#{port}/__dev"
|
|
124
|
+
puts " Debug: #{is_debug ? 'ON' : 'OFF'} (Log level: #{log_level})"
|
|
93
125
|
puts ""
|
|
94
126
|
rescue
|
|
95
|
-
puts "
|
|
127
|
+
puts "#{color}TINA4 Ruby v#{VERSION}#{reset}"
|
|
96
128
|
end
|
|
97
129
|
|
|
98
130
|
def initialize!(root_dir = Dir.pwd)
|
|
@@ -102,11 +134,11 @@ module Tina4
|
|
|
102
134
|
print_banner
|
|
103
135
|
|
|
104
136
|
# Load environment
|
|
105
|
-
Tina4::Env.
|
|
137
|
+
Tina4::Env.load_env(root_dir)
|
|
106
138
|
|
|
107
139
|
# Setup debug logging
|
|
108
|
-
Tina4::
|
|
109
|
-
Tina4::
|
|
140
|
+
Tina4::Log.setup(root_dir)
|
|
141
|
+
Tina4::Log.info("Tina4 Ruby v#{VERSION} initializing...")
|
|
110
142
|
|
|
111
143
|
# Setup auth keys
|
|
112
144
|
Tina4::Auth.setup(root_dir)
|
|
@@ -120,7 +152,7 @@ module Tina4
|
|
|
120
152
|
# Auto-discover routes
|
|
121
153
|
auto_discover(root_dir)
|
|
122
154
|
|
|
123
|
-
Tina4::
|
|
155
|
+
Tina4::Log.info("Tina4 initialized successfully")
|
|
124
156
|
end
|
|
125
157
|
|
|
126
158
|
# DSL methods for route registration
|
|
@@ -217,6 +249,20 @@ module Tina4
|
|
|
217
249
|
Tina4::Localization.t(key, **options)
|
|
218
250
|
end
|
|
219
251
|
|
|
252
|
+
# Service runner DSL
|
|
253
|
+
def service(name, options = {}, &block)
|
|
254
|
+
Tina4::ServiceRunner.register(name, nil, options, &block)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# DI container shortcuts
|
|
258
|
+
def register(name, instance = nil, &block)
|
|
259
|
+
Tina4::Container.register(name, instance, &block)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def resolve(name)
|
|
263
|
+
Tina4::Container.resolve(name)
|
|
264
|
+
end
|
|
265
|
+
|
|
220
266
|
private
|
|
221
267
|
|
|
222
268
|
# Resolve auth option for route registration
|
|
@@ -240,9 +286,9 @@ module Tina4
|
|
|
240
286
|
if db_url && !db_url.empty?
|
|
241
287
|
begin
|
|
242
288
|
@database = Tina4::Database.new(db_url)
|
|
243
|
-
Tina4::
|
|
289
|
+
Tina4::Log.info("Database connected: #{db_url.sub(/:[^:@]+@/, ':***@')}")
|
|
244
290
|
rescue => e
|
|
245
|
-
Tina4::
|
|
291
|
+
Tina4::Log.error("Database connection failed: #{e.message}")
|
|
246
292
|
end
|
|
247
293
|
end
|
|
248
294
|
end
|
|
@@ -256,9 +302,9 @@ module Tina4
|
|
|
256
302
|
Dir.glob(File.join(full_dir, "**/*.rb")).sort.each do |file|
|
|
257
303
|
begin
|
|
258
304
|
load file
|
|
259
|
-
Tina4::
|
|
305
|
+
Tina4::Log.debug("Auto-loaded: #{file}")
|
|
260
306
|
rescue => e
|
|
261
|
-
Tina4::
|
|
307
|
+
Tina4::Log.error("Failed to load #{file}: #{e.message}")
|
|
262
308
|
end
|
|
263
309
|
end
|
|
264
310
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tina4ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tina4 Team
|
|
@@ -93,20 +93,6 @@ dependencies:
|
|
|
93
93
|
- - "~>"
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
95
|
version: '3.1'
|
|
96
|
-
- !ruby/object:Gem::Dependency
|
|
97
|
-
name: thor
|
|
98
|
-
requirement: !ruby/object:Gem::Requirement
|
|
99
|
-
requirements:
|
|
100
|
-
- - "~>"
|
|
101
|
-
- !ruby/object:Gem::Version
|
|
102
|
-
version: '1.3'
|
|
103
|
-
type: :runtime
|
|
104
|
-
prerelease: false
|
|
105
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
-
requirements:
|
|
107
|
-
- - "~>"
|
|
108
|
-
- !ruby/object:Gem::Version
|
|
109
|
-
version: '1.3'
|
|
110
96
|
- !ruby/object:Gem::Dependency
|
|
111
97
|
name: json
|
|
112
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -237,23 +223,31 @@ description: A lightweight, zero-configuration, Windows-friendly Ruby web framew
|
|
|
237
223
|
email:
|
|
238
224
|
- info@tina4.com
|
|
239
225
|
executables:
|
|
240
|
-
-
|
|
226
|
+
- tina4ruby
|
|
241
227
|
extensions: []
|
|
242
228
|
extra_rdoc_files: []
|
|
243
229
|
files:
|
|
244
230
|
- CHANGELOG.md
|
|
245
231
|
- LICENSE.txt
|
|
246
232
|
- README.md
|
|
247
|
-
- exe/
|
|
233
|
+
- exe/tina4ruby
|
|
248
234
|
- lib/tina4.rb
|
|
235
|
+
- lib/tina4/ai.rb
|
|
249
236
|
- lib/tina4/api.rb
|
|
250
237
|
- lib/tina4/auth.rb
|
|
238
|
+
- lib/tina4/auto_crud.rb
|
|
251
239
|
- lib/tina4/cli.rb
|
|
240
|
+
- lib/tina4/constants.rb
|
|
241
|
+
- lib/tina4/container.rb
|
|
242
|
+
- lib/tina4/cors.rb
|
|
252
243
|
- lib/tina4/crud.rb
|
|
253
244
|
- lib/tina4/database.rb
|
|
245
|
+
- lib/tina4/database/sqlite3_adapter.rb
|
|
254
246
|
- lib/tina4/database_result.rb
|
|
255
247
|
- lib/tina4/debug.rb
|
|
256
248
|
- lib/tina4/dev.rb
|
|
249
|
+
- lib/tina4/dev_admin.rb
|
|
250
|
+
- lib/tina4/dev_mailbox.rb
|
|
257
251
|
- lib/tina4/dev_reload.rb
|
|
258
252
|
- lib/tina4/drivers/firebird_driver.rb
|
|
259
253
|
- lib/tina4/drivers/mssql_driver.rb
|
|
@@ -261,23 +255,53 @@ files:
|
|
|
261
255
|
- lib/tina4/drivers/postgres_driver.rb
|
|
262
256
|
- lib/tina4/drivers/sqlite_driver.rb
|
|
263
257
|
- lib/tina4/env.rb
|
|
258
|
+
- lib/tina4/error_overlay.rb
|
|
259
|
+
- lib/tina4/events.rb
|
|
264
260
|
- lib/tina4/field_types.rb
|
|
261
|
+
- lib/tina4/frond.rb
|
|
262
|
+
- lib/tina4/gallery/auth/meta.json
|
|
263
|
+
- lib/tina4/gallery/auth/src/routes/api/gallery_auth.rb
|
|
264
|
+
- lib/tina4/gallery/database/meta.json
|
|
265
|
+
- lib/tina4/gallery/database/src/routes/api/gallery_db.rb
|
|
266
|
+
- lib/tina4/gallery/error-overlay/meta.json
|
|
267
|
+
- lib/tina4/gallery/error-overlay/src/routes/api/gallery_crash.rb
|
|
268
|
+
- lib/tina4/gallery/orm/meta.json
|
|
269
|
+
- lib/tina4/gallery/orm/src/routes/api/gallery_products.rb
|
|
270
|
+
- lib/tina4/gallery/queue/meta.json
|
|
271
|
+
- lib/tina4/gallery/queue/src/routes/api/gallery_queue.rb
|
|
272
|
+
- lib/tina4/gallery/rest-api/meta.json
|
|
273
|
+
- lib/tina4/gallery/rest-api/src/routes/api/gallery_hello.rb
|
|
274
|
+
- lib/tina4/gallery/templates/meta.json
|
|
275
|
+
- lib/tina4/gallery/templates/src/routes/gallery_page.rb
|
|
276
|
+
- lib/tina4/gallery/templates/src/templates/gallery_page.twig
|
|
265
277
|
- lib/tina4/graphql.rb
|
|
278
|
+
- lib/tina4/health.rb
|
|
279
|
+
- lib/tina4/html_element.rb
|
|
266
280
|
- lib/tina4/localization.rb
|
|
281
|
+
- lib/tina4/log.rb
|
|
282
|
+
- lib/tina4/messenger.rb
|
|
267
283
|
- lib/tina4/middleware.rb
|
|
268
284
|
- lib/tina4/migration.rb
|
|
269
285
|
- lib/tina4/orm.rb
|
|
270
286
|
- lib/tina4/public/css/tina4.css
|
|
271
287
|
- lib/tina4/public/css/tina4.min.css
|
|
272
|
-
- lib/tina4/public/
|
|
273
|
-
- lib/tina4/public/
|
|
288
|
+
- lib/tina4/public/favicon.ico
|
|
289
|
+
- lib/tina4/public/images/logo.svg
|
|
290
|
+
- lib/tina4/public/images/tina4-logo-icon.webp
|
|
291
|
+
- lib/tina4/public/js/frond.min.js
|
|
292
|
+
- lib/tina4/public/js/tina4-dev-admin.min.js
|
|
293
|
+
- lib/tina4/public/js/tina4.min.js
|
|
294
|
+
- lib/tina4/public/swagger/index.html
|
|
295
|
+
- lib/tina4/public/swagger/oauth2-redirect.html
|
|
274
296
|
- lib/tina4/queue.rb
|
|
275
297
|
- lib/tina4/queue_backends/kafka_backend.rb
|
|
276
298
|
- lib/tina4/queue_backends/lite_backend.rb
|
|
277
299
|
- lib/tina4/queue_backends/rabbitmq_backend.rb
|
|
278
300
|
- lib/tina4/rack_app.rb
|
|
301
|
+
- lib/tina4/rate_limiter.rb
|
|
279
302
|
- lib/tina4/request.rb
|
|
280
303
|
- lib/tina4/response.rb
|
|
304
|
+
- lib/tina4/response_cache.rb
|
|
281
305
|
- lib/tina4/router.rb
|
|
282
306
|
- lib/tina4/scss/tina4css/_alerts.scss
|
|
283
307
|
- lib/tina4/scss/tina4css/_badges.scss
|
|
@@ -297,16 +321,25 @@ files:
|
|
|
297
321
|
- lib/tina4/scss/tina4css/tina4.scss
|
|
298
322
|
- lib/tina4/scss_compiler.rb
|
|
299
323
|
- lib/tina4/seeder.rb
|
|
324
|
+
- lib/tina4/service_runner.rb
|
|
300
325
|
- lib/tina4/session.rb
|
|
301
326
|
- lib/tina4/session_handlers/file_handler.rb
|
|
302
327
|
- lib/tina4/session_handlers/mongo_handler.rb
|
|
303
328
|
- lib/tina4/session_handlers/redis_handler.rb
|
|
329
|
+
- lib/tina4/session_handlers/valkey_handler.rb
|
|
330
|
+
- lib/tina4/shutdown.rb
|
|
331
|
+
- lib/tina4/sql_translation.rb
|
|
304
332
|
- lib/tina4/swagger.rb
|
|
305
333
|
- lib/tina4/template.rb
|
|
306
334
|
- lib/tina4/templates/base.twig
|
|
335
|
+
- lib/tina4/templates/errors/302.twig
|
|
336
|
+
- lib/tina4/templates/errors/401.twig
|
|
307
337
|
- lib/tina4/templates/errors/403.twig
|
|
308
338
|
- lib/tina4/templates/errors/404.twig
|
|
309
339
|
- lib/tina4/templates/errors/500.twig
|
|
340
|
+
- lib/tina4/templates/errors/502.twig
|
|
341
|
+
- lib/tina4/templates/errors/503.twig
|
|
342
|
+
- lib/tina4/templates/errors/base.twig
|
|
310
343
|
- lib/tina4/testing.rb
|
|
311
344
|
- lib/tina4/version.rb
|
|
312
345
|
- lib/tina4/webserver.rb
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tina4 CSS — Lightweight JS components
|
|
3
|
-
* Replaces Bootstrap's JavaScript for: modals, alerts, navbar toggler
|
|
4
|
-
* ~3KB unminified, zero dependencies
|
|
5
|
-
*/
|
|
6
|
-
(function () {
|
|
7
|
-
"use strict";
|
|
8
|
-
|
|
9
|
-
// ── Modals ──────────────────────────────────────────────────
|
|
10
|
-
// Usage: <button data-t4-toggle="modal" data-t4-target="#myModal">Open</button>
|
|
11
|
-
// <button data-t4-dismiss="modal">Close</button>
|
|
12
|
-
// Also supports Bootstrap syntax: data-bs-toggle, data-bs-target, data-bs-dismiss
|
|
13
|
-
|
|
14
|
-
function getModalEl(selector) {
|
|
15
|
-
if (!selector) return null;
|
|
16
|
-
return document.querySelector(selector);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function openModal(modal) {
|
|
20
|
-
if (!modal) return;
|
|
21
|
-
// Create backdrop if not exists
|
|
22
|
-
var backdrop = modal._t4Backdrop;
|
|
23
|
-
if (!backdrop) {
|
|
24
|
-
backdrop = document.createElement("div");
|
|
25
|
-
backdrop.className = "modal-backdrop";
|
|
26
|
-
document.body.appendChild(backdrop);
|
|
27
|
-
modal._t4Backdrop = backdrop;
|
|
28
|
-
backdrop.addEventListener("click", function () {
|
|
29
|
-
closeModal(modal);
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
modal.style.display = "block";
|
|
33
|
-
backdrop.style.display = "block";
|
|
34
|
-
// Force reflow then add .show for transition
|
|
35
|
-
void modal.offsetHeight;
|
|
36
|
-
modal.classList.add("show");
|
|
37
|
-
backdrop.classList.add("show");
|
|
38
|
-
document.body.style.overflow = "hidden";
|
|
39
|
-
// Focus trap — focus first focusable element
|
|
40
|
-
var focusable = modal.querySelector("input, select, textarea, button, [tabindex]");
|
|
41
|
-
if (focusable) focusable.focus();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function closeModal(modal) {
|
|
45
|
-
if (!modal) return;
|
|
46
|
-
modal.classList.remove("show");
|
|
47
|
-
var backdrop = modal._t4Backdrop;
|
|
48
|
-
if (backdrop) backdrop.classList.remove("show");
|
|
49
|
-
// Wait for transition
|
|
50
|
-
setTimeout(function () {
|
|
51
|
-
modal.style.display = "none";
|
|
52
|
-
if (backdrop) backdrop.style.display = "none";
|
|
53
|
-
document.body.style.overflow = "";
|
|
54
|
-
}, 150);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Delegated click handler for modal triggers
|
|
58
|
-
document.addEventListener("click", function (e) {
|
|
59
|
-
var trigger = e.target.closest("[data-t4-toggle='modal'], [data-bs-toggle='modal']");
|
|
60
|
-
if (trigger) {
|
|
61
|
-
e.preventDefault();
|
|
62
|
-
var target = trigger.getAttribute("data-t4-target") || trigger.getAttribute("data-bs-target") || trigger.getAttribute("href");
|
|
63
|
-
var modal = getModalEl(target);
|
|
64
|
-
if (modal) openModal(modal);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Dismiss button
|
|
69
|
-
var dismiss = e.target.closest("[data-t4-dismiss='modal'], [data-bs-dismiss='modal'], .btn-close");
|
|
70
|
-
if (dismiss) {
|
|
71
|
-
var modal = dismiss.closest(".modal");
|
|
72
|
-
if (modal) closeModal(modal);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// ESC key closes top modal
|
|
78
|
-
document.addEventListener("keydown", function (e) {
|
|
79
|
-
if (e.key === "Escape") {
|
|
80
|
-
var modals = document.querySelectorAll(".modal.show");
|
|
81
|
-
if (modals.length > 0) closeModal(modals[modals.length - 1]);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// ── Alerts (dismissible) ────────────────────────────────────
|
|
86
|
-
// Usage: <div class="alert alert-danger alert-dismissible">
|
|
87
|
-
// Message <button class="btn-close" data-t4-dismiss="alert">×</button>
|
|
88
|
-
// </div>
|
|
89
|
-
|
|
90
|
-
document.addEventListener("click", function (e) {
|
|
91
|
-
var dismiss = e.target.closest("[data-t4-dismiss='alert'], [data-bs-dismiss='alert']");
|
|
92
|
-
if (dismiss) {
|
|
93
|
-
var alert = dismiss.closest(".alert");
|
|
94
|
-
if (alert) {
|
|
95
|
-
alert.style.opacity = "0";
|
|
96
|
-
setTimeout(function () { alert.remove(); }, 150);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// ── Navbar toggler ──────────────────────────────────────────
|
|
102
|
-
// Usage: <button class="navbar-toggler" data-t4-toggle="collapse" data-t4-target="#navContent">
|
|
103
|
-
// ☰
|
|
104
|
-
// </button>
|
|
105
|
-
// <div class="navbar-collapse collapse" id="navContent">...</div>
|
|
106
|
-
|
|
107
|
-
document.addEventListener("click", function (e) {
|
|
108
|
-
var toggler = e.target.closest("[data-t4-toggle='collapse'], [data-bs-toggle='collapse']");
|
|
109
|
-
if (toggler) {
|
|
110
|
-
e.preventDefault();
|
|
111
|
-
var target = toggler.getAttribute("data-t4-target") || toggler.getAttribute("data-bs-target") || toggler.getAttribute("href");
|
|
112
|
-
var el = document.querySelector(target);
|
|
113
|
-
if (el) {
|
|
114
|
-
el.classList.toggle("show");
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// ── Programmatic API ────────────────────────────────────────
|
|
120
|
-
// window.tina4.modal.open("#myModal")
|
|
121
|
-
// window.tina4.modal.close("#myModal")
|
|
122
|
-
|
|
123
|
-
window.tina4 = window.tina4 || {};
|
|
124
|
-
window.tina4.modal = {
|
|
125
|
-
open: function (selector) {
|
|
126
|
-
var modal = typeof selector === "string" ? document.querySelector(selector) : selector;
|
|
127
|
-
openModal(modal);
|
|
128
|
-
},
|
|
129
|
-
close: function (selector) {
|
|
130
|
-
var modal = typeof selector === "string" ? document.querySelector(selector) : selector;
|
|
131
|
-
closeModal(modal);
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
})();
|