tina4ruby 3.13.149 → 3.13.151
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 +26 -0
- data/lib/tina4/auth.rb +3 -3
- data/lib/tina4/cli.rb +1 -1
- data/lib/tina4/crud.rb +7 -7
- data/lib/tina4/dev_admin.rb +14 -0
- data/lib/tina4/drivers/mongodb_driver.rb +48 -13
- data/lib/tina4/drivers/mssql_driver.rb +6 -1
- data/lib/tina4/form_parser.rb +38 -4
- data/lib/tina4/frond.rb +151 -20
- data/lib/tina4/mcp.rb +36 -12
- data/lib/tina4/metrics.rb +5 -1
- data/lib/tina4/middleware.rb +10 -1
- data/lib/tina4/plan.rb +3 -3
- data/lib/tina4/point.rb +1 -1
- data/lib/tina4/project_index.rb +1 -1
- data/lib/tina4/public/bundled-component-provenance.json +2 -2
- data/lib/tina4/public/js/tina4-dev-admin-split.html +202 -0
- data/lib/tina4/public/js/tina4-dev-admin.min.js +147 -138
- data/lib/tina4/rack_app.rb +4 -1
- data/lib/tina4/realtime/s3_client.rb +240 -0
- data/lib/tina4/realtime/s3_storage.rb +15 -28
- data/lib/tina4/realtime/storage.rb +4 -5
- data/lib/tina4/realtime.rb +2 -1
- data/lib/tina4/request.rb +41 -3
- data/lib/tina4/response_cache.rb +9 -1
- data/lib/tina4/router.rb +1 -1
- data/lib/tina4/sql_translator.rb +5 -3
- data/lib/tina4/template.rb +32 -17
- data/lib/tina4/templates/crud/form.twig +5 -5
- data/lib/tina4/templates/crud/table.twig +2 -2
- data/lib/tina4/templates/errors/302.twig +4 -3
- data/lib/tina4/version.rb +1 -1
- data/lib/tina4/webserver.rb +1 -1
- metadata +4 -2
|
@@ -3,23 +3,23 @@
|
|
|
3
3
|
|
|
4
4
|
Override: drop your own templates/crud/form.twig to change how inputs render.
|
|
5
5
|
|
|
6
|
-
fields - one per input: { id, name, label, value, placeholder,
|
|
6
|
+
fields - one per input: { id, name, label, value, placeholder, required (bool),
|
|
7
7
|
and exactly ONE control flag: input (with type) | textarea | checkbox
|
|
8
|
-
(
|
|
9
|
-
wrap - render the <form> wrapper;
|
|
8
|
+
(checked bool) | select (options_html) }.
|
|
9
|
+
wrap - render the <form> wrapper; form_id/action/form_method set it
|
|
10
10
|
edit - add the hidden primary-key input (edit modal)
|
|
11
11
|
modal_footer- render the Cancel/Save modal buttons; submit_button - a plain Submit
|
|
12
12
|
|
|
13
13
|
No inline styles or on*= handlers: the modal buttons carry data-crud-action and
|
|
14
14
|
are wired by the page script's delegated listener (ADR-0088).
|
|
15
15
|
#}
|
|
16
|
-
{% if wrap %}<form{{
|
|
16
|
+
{% if wrap %}<form{% if form_id %} id="{{ form_id }}"{% endif %} action="{{ action }}" method="{{ form_method }}" class="needs-validation" data-crud-form="1">{% endif %}
|
|
17
17
|
{% if method_override %}<input type="hidden" name="_method" value="{{ method_override }}">{% endif %}
|
|
18
18
|
{% if edit %}<input type="hidden" id="{{ mode }}-pk-value" name="{{ pk }}">{% endif %}
|
|
19
19
|
{% if modal_footer %}<div class="crud-errors" data-crud-errors hidden></div>{% endif %}
|
|
20
20
|
{% for field in fields %}<div class="mb-3">
|
|
21
21
|
<label for="{{ field.id }}" class="form-label">{{ field.label }}</label>
|
|
22
|
-
{% if field.textarea %}<textarea class="form-control" id="{{ field.id }}" name="{{ field.name }}"{
|
|
22
|
+
{% if field.textarea %}<textarea class="form-control" id="{{ field.id }}" name="{{ field.name }}"{% if field.required %} required{% endif %}>{{ field.value }}</textarea>{% endif %}{% if field.checkbox %}<div class="form-check"><input class="form-check-input" type="checkbox" id="{{ field.id }}" name="{{ field.name }}"{% if field.checked %} checked{% endif %}></div>{% endif %}{% if field.select %}<select class="form-select" id="{{ field.id }}" name="{{ field.name }}"{% if field.required %} required{% endif %}>{{ field.options_html|raw }}</select>{% endif %}{% if field.input %}<input type="{{ field.type }}" class="form-control" id="{{ field.id }}" name="{{ field.name }}" value="{{ field.value }}" placeholder="{{ field.placeholder }}"{% if field.required %} required{% endif %}>{% endif %}
|
|
23
23
|
</div>
|
|
24
24
|
{% endfor %}
|
|
25
25
|
{% if modal_footer %}<div class="modal-footer"><button type="button" class="btn btn-secondary" data-crud-action="close" data-crud-modal="{{ mode }}">Cancel</button><button type="button" class="btn btn-primary" data-crud-action="save" data-crud-mode="{{ mode }}">Save</button></div>{% endif %}{% if submit_button %}<button type="submit" class="btn btn-primary">Submit</button>{% endif %}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
empty - true when there are no rows
|
|
12
12
|
colspan - column count + 1 (for the empty row)
|
|
13
13
|
editable - inline-edit table (Save/Delete); readonly - view table (Edit/Delete)
|
|
14
|
-
table_name,
|
|
14
|
+
table_name, table_id, inline_script
|
|
15
15
|
|
|
16
16
|
Alignment: each header/cell carries a tina4-css class (text-start for text,
|
|
17
17
|
text-end for numbers). Actions is always text-end. No inline styles (ADR-0088).
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
re-renders <tbody data-crud-body> over fetch() as the user searches/sorts/pages.
|
|
21
21
|
#}
|
|
22
22
|
<div class="table-responsive">
|
|
23
|
-
<table class="table table-striped table-hover"{{
|
|
23
|
+
<table class="table table-striped table-hover"{% if table_id %} id="{{ table_id }}"{% endif %}>
|
|
24
24
|
<thead class="table-dark"><tr>
|
|
25
25
|
{% for header in headers %}{% if header.sortable %}<th class="{{ header.align }}"><a class="sort-link" href="{{ header.url }}" data-crud-sort="{{ header.col }}" data-crud-dir="{{ header.next_dir }}">{{ header.label }}{{ header.indicator|raw }}</a></th>{% endif %}{% if header.plain %}<th class="{{ header.align }}">{{ header.label }}</th>{% endif %}{% endfor %}<th class="text-end">Actions</th>
|
|
26
26
|
</tr></thead>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{% extends "errors/base.twig" %}
|
|
2
2
|
{% block title %}Redirecting…{% endblock %}
|
|
3
|
-
{% block meta %}<meta http-equiv="refresh" content="0;url={{
|
|
3
|
+
{% block meta %}{% set p1 = redirect_url|slice(0,1) %}{% set p2 = redirect_url|slice(0,2) %}{% set p7 = redirect_url|slice(0,7) %}{% set p8 = redirect_url|slice(0,8) %}{% set rel = (p1 == '/') ? ((p2 == '//') ? 'no' : 'yes') : 'no' %}{% set safe_redirect_url = (rel == 'yes' or p7 == 'http://' or p8 == 'https://') ? redirect_url : '/' %}<meta http-equiv="refresh" content="0;url={{ safe_redirect_url }}">{% endblock %}
|
|
4
4
|
{% block extra_styles %}
|
|
5
5
|
.spinner { display: inline-block; width: 1.5rem; height: 1.5rem; border: 3px solid var(--border); border-top-color: var(--primary); border-radius: 50%; animation: spin 0.8s linear infinite; margin-bottom: 1rem; }
|
|
6
6
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
7
7
|
{% endblock %}
|
|
8
8
|
{% block content %}
|
|
9
|
+
{% set p1 = redirect_url|slice(0,1) %}{% set p2 = redirect_url|slice(0,2) %}{% set p7 = redirect_url|slice(0,7) %}{% set p8 = redirect_url|slice(0,8) %}{% set rel = (p1 == '/') ? ((p2 == '//') ? 'no' : 'yes') : 'no' %}{% set safe_redirect_url = (rel == 'yes' or p7 == 'http://' or p8 == 'https://') ? redirect_url : '/' %}
|
|
9
10
|
<div class="spinner"></div>
|
|
10
11
|
<div class="error-title">Redirecting…</div>
|
|
11
12
|
<div class="error-msg">You are being redirected to a new location.</div>
|
|
12
|
-
<div class="error-path c-primary">{{
|
|
13
|
-
<a href="{{
|
|
13
|
+
<div class="error-path c-primary">{{ safe_redirect_url }}</div>
|
|
14
|
+
<a href="{{ safe_redirect_url }}" class="error-home">Click here if not redirected</a>
|
|
14
15
|
{% endblock %}
|
data/lib/tina4/version.rb
CHANGED
data/lib/tina4/webserver.rb
CHANGED
|
@@ -199,7 +199,7 @@ module Tina4
|
|
|
199
199
|
# @param host [String] the host the main socket binds
|
|
200
200
|
# @return [Array<String>] extra bind addresses (possibly empty)
|
|
201
201
|
def self.loopback_bind_hosts(host)
|
|
202
|
-
normalized = host.to_s.strip.downcase.gsub(/\A\[
|
|
202
|
+
normalized = host.to_s.strip.downcase.gsub(/\A\[++|\]++\z/, "")
|
|
203
203
|
case normalized
|
|
204
204
|
when "localhost" then ["127.0.0.1", "::1"]
|
|
205
205
|
when "127.0.0.1", "0.0.0.0" then ["::1"]
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tina4ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.13.
|
|
4
|
+
version: 3.13.151
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tina4 Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: sqlite3
|
|
@@ -293,6 +293,7 @@ files:
|
|
|
293
293
|
- lib/tina4/public/images/tina4-logo-icon.webp
|
|
294
294
|
- lib/tina4/public/js/frond.js
|
|
295
295
|
- lib/tina4/public/js/frond.min.js
|
|
296
|
+
- lib/tina4/public/js/tina4-dev-admin-split.html
|
|
296
297
|
- lib/tina4/public/js/tina4-dev-admin.min.js
|
|
297
298
|
- lib/tina4/public/js/tina4.min.js
|
|
298
299
|
- lib/tina4/public/js/tina4js.min.js
|
|
@@ -321,6 +322,7 @@ files:
|
|
|
321
322
|
- lib/tina4/realtime/channel_member.rb
|
|
322
323
|
- lib/tina4/realtime/local_storage.rb
|
|
323
324
|
- lib/tina4/realtime/message.rb
|
|
325
|
+
- lib/tina4/realtime/s3_client.rb
|
|
324
326
|
- lib/tina4/realtime/s3_storage.rb
|
|
325
327
|
- lib/tina4/realtime/storage.rb
|
|
326
328
|
- lib/tina4/realtime/storage_backend.rb
|