DEV: Introduce experimental `type: objects` theme setting (#25538)

Why this change?

This commit introduces an experimental `type: objects` theme setting
which will allow theme developers to store a collection of objects as
JSON in the database. Currently, the feature is still in development and
this commit is simply setting up the ground work for us to introduce the
feature in smaller pieces.

What does this change do?

1. Adds a `json_value` column as `jsonb` data type to the `theme_settings` table.
2. Adds a `experimental_objects_type_for_theme_settings` site setting to
   determine whether `ThemeSetting` records of with the `objects` data
   type can be created.
3. Updates `ThemeSettingsManager` to support read/write access from the
   `ThemeSettings#json_value` column.
This commit is contained in:
Alan Guo Xiang Tan 2024-02-08 10:20:59 +08:00 committed by GitHub
parent 8eb4bf07a6
commit 9f884cdaab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 132 additions and 30 deletions

View File

@ -5,8 +5,12 @@ class ThemeSetting < ActiveRecord::Base
has_many :upload_references, as: :target, dependent: :destroy
TYPES_ENUM =
Enum.new(integer: 0, float: 1, string: 2, bool: 3, list: 4, enum: 5, upload: 6, objects: 7)
validates_presence_of :name, :theme
validates :data_type, numericality: { only_integer: true }
before_validation :objects_type_enabled
validates :data_type, inclusion: { in: TYPES_ENUM.values }
validates :name, length: { maximum: 255 }
after_save :clear_settings_cache
@ -24,7 +28,7 @@ class ThemeSetting < ActiveRecord::Base
end
def self.types
@types ||= Enum.new(integer: 0, float: 1, string: 2, bool: 3, list: 4, enum: 5, upload: 6)
TYPES_ENUM
end
def self.acceptable_value_for_type?(value, type)
@ -37,6 +41,9 @@ class ThemeSetting < ActiveRecord::Base
value.is_a?(TrueClass) || value.is_a?(FalseClass)
when self.types[:list]
value.is_a?(String)
when self.types[:objects]
# TODO: This is a simple check now but we want to validate the default objects agianst the schema as well.
value.is_a?(Array)
else
true
end
@ -62,6 +69,15 @@ class ThemeSetting < ActiveRecord::Base
types[:bool]
end
end
private
def objects_type_enabled
if self.data_type == ThemeSetting.types[:objects] &&
!SiteSetting.experimental_objects_type_for_theme_settings
self.data_type = nil
end
end
end
# == Schema Information
@ -75,4 +91,5 @@ end
# theme_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# json_value :jsonb
#

View File

@ -114,7 +114,7 @@ ar:
optimized_link: روابط الصور المحسَّنة سريعة الزوال ولا يجب تضمينها في الرمز البرمجي المصدري للسمة.
settings_errors:
invalid_yaml: "ملف YAML الذي أدخلته غير صالح."
data_type_not_a_number: "نوع الإعداد `%{name}` غير مدعوم. الأنواع المدعومة هي: `integer`، و`bool`، و`list`، و`enum` و`upload`"
data_type_inclusion: "نوع الإعداد `%{name}` غير مدعوم. الأنواع المدعومة هي: `integer`، و`bool`، و`list`، و`enum` و`upload`"
name_too_long: "يوجد إعداد باسم طويل جدًا. الحد الأقصى للطول هو 255"
default_value_missing: "لا توجد قيمة افتراضية للإعداد `%{name}`"
default_not_match_type: "لا تتطابق القيمة الافتراضية للإعداد `%{name}` مع نوعه."

View File

@ -78,7 +78,7 @@ da:
optimized_link: Optimerede billedlinks er midlertidige og bør ikke indgå i tema kildekode.
settings_errors:
invalid_yaml: "Leveret YAML er ugyldig."
data_type_not_a_number: "Indstilling`%{name}` typen understøttes ikke. Understøttede typer er `integer`, `bool`, `list`, `enum` og `upload`"
data_type_inclusion: "Indstilling`%{name}` typen understøttes ikke. Understøttede typer er `integer`, `bool`, `list`, `enum` og `upload`"
name_too_long: "Der er en indstilling med et for langt navn. Maksimal længde er 255"
default_value_missing: "Indstilling af `%{name}` har ingen standard værdi"
default_not_match_type: "Indstilling af `%{name}`s standard værdi's type stemmer ikke overens med den type fundet i indstillingerne."

View File

@ -110,7 +110,7 @@ de:
optimized_link: Optimierte Bildlinks sind flüchtig und sollten nicht in den Theme-Quellcode eingebunden werden.
settings_errors:
invalid_yaml: "Der YAML-Code ist ungültig."
data_type_not_a_number: "Typ der Einstellung `%{name}` wird nicht unterstützt. Unterstützte Typen sind `integer`, `bool`, `list`, `enum` und `upload`"
data_type_inclusion: "Typ der Einstellung `%{name}` wird nicht unterstützt. Unterstützte Typen sind `integer`, `bool`, `list`, `enum` und `upload`"
name_too_long: "Es gibt eine Einstellung mit einem zu langen Namen. Die maximale Länge beträgt 255 Zeichen."
default_value_missing: "Einstellung `%{name}` hat keinen Standardwert."
default_not_match_type: "Bei der Einstellung `%{name}` stimmt der Datentyp des Standardwerts nicht mit dem Datentyp der Einstellung überein."

View File

@ -120,7 +120,7 @@ en:
optimized_link: Optimized image links are ephemeral and should not be included in theme source code.
settings_errors:
invalid_yaml: "Provided YAML is invalid."
data_type_not_a_number: "Setting `%{name}` type is unsupported. Supported types are `integer`, `bool`, `list`, `enum` and `upload`"
data_type_inclusion: "Setting `%{name}` type is unsupported. Supported types are `integer`, `bool`, `list`, `enum` and `upload`"
name_too_long: "There is a setting with a too long name. Maximum length is 255"
default_value_missing: "Setting `%{name}` has no default value"
default_not_match_type: "Setting `%{name}` default value's type doesn't match with the setting type."

View File

@ -110,7 +110,7 @@ es:
optimized_link: Los enlaces de imagen optimizados son efímeros y no deben incluirse en el código fuente del tema.
settings_errors:
invalid_yaml: "El YAML provisto no es válido."
data_type_not_a_number: "Tipo de ajuste «%{name}» no soportado. Los tipos soportados son «integer», «bool», «list», «enum» y «upload»"
data_type_inclusion: "Tipo de ajuste «%{name}» no soportado. Los tipos soportados son «integer», «bool», «list», «enum» y «upload»"
name_too_long: "Hay un ajuste con un nombre muy largo. La cantidad máxima de caracteres es 255"
default_value_missing: "El ajuste «%{name}» no tiene valor por defecto"
default_not_match_type: "El tipo de valor por defecto para el ajuste «%{name}» no coincide con el tipo de ajuste."

View File

@ -110,7 +110,7 @@ fi:
optimized_link: Optimoidut kuvalinkit ovat lyhytikäisiä, eikä niitä tulisi sisällyttää teeman lähdekoodiin.
settings_errors:
invalid_yaml: "Annettu YAML ei kelpaa"
data_type_not_a_number: "Tietotyypiksi ei ole mahdollista asettaa `%{name}`. Tuettuja tietotyyppejä ovat `integer`, `bool`, `list`, `enum` ja `upload`"
data_type_inclusion: "Tietotyypiksi ei ole mahdollista asettaa `%{name}`. Tuettuja tietotyyppejä ovat `integer`, `bool`, `list`, `enum` ja `upload`"
name_too_long: "Jollain asetuksella on liian pitkä nimi. Enimmäispituus on 255."
default_value_missing: "Asetuksella \"%{name}\" ei ole oletusarvoa"
default_not_match_type: "Asetuksen \"%{name}\" oletusarvo ei sovi asetuksen tyyppiin."

View File

@ -110,7 +110,7 @@ fr:
optimized_link: Les liens optimisés d'images sont éphémères et ne devraient pas être inclus dans le code source d'un thème.
settings_errors:
invalid_yaml: "Le YAML est invalide"
data_type_not_a_number: "Le type « %{name} » n'est pas supporté. Les types supportés sont « integer », « bool », « list », « enum » et « upload »"
data_type_inclusion: "Le type « %{name} » n'est pas supporté. Les types supportés sont « integer », « bool », « list », « enum » et « upload »"
name_too_long: "Il y a un paramètre avec un nom trop long. Longueur maximum 255"
default_value_missing: "Le paramètre « %{name} » n'a pas de valeur par défaut"
default_not_match_type: "Le type de la valeur par défaut du paramètre « %{name} » ne correspond pas au type du paramètre."

View File

@ -78,7 +78,7 @@ gl:
optimized_link: As ligazóns de imaxe optimizadas son efémeras e non deberían ser incluídas no código fonte do tema.
settings_errors:
invalid_yaml: "O YAML proporcionado non é válido."
data_type_not_a_number: "Tipo de axuste `%{name}` non compatible. Os tipos compatibles son `integer`, `bool`, `list`, `enum` e `upload`"
data_type_inclusion: "Tipo de axuste `%{name}` non compatible. Os tipos compatibles son `integer`, `bool`, `list`, `enum` e `upload`"
name_too_long: "Hai un axuste cun nome demasiado longo. A lonxitude máxima é de 255 caracteres"
default_value_missing: "O axuste '%{name}' non ten un valor predefinido"
default_not_match_type: "O tipo de valor predefinido para o axuste `%{name}` non coincide co tipo de axuste."

View File

@ -112,7 +112,7 @@ he:
optimized_link: קישורים משופרים לתמונות הם בני חלוף ואין לכלול אותם בקוד המקור של ערכת העיצוב.
settings_errors:
invalid_yaml: "ה־YAML שסופק שגוי."
data_type_not_a_number: "סוג ההגדרה `%{name}` אינו נתמך. הסוגים הנתמכים הם: `integer`, `bool`, `list`, `enum` ו־`upload`"
data_type_inclusion: "סוג ההגדרה `%{name}` אינו נתמך. הסוגים הנתמכים הם: `integer`, `bool`, `list`, `enum` ו־`upload`"
name_too_long: "קיימת הגדרה עם שם ארוך מדי. האורך המרבי הוא 255"
default_value_missing: "להגדרה `%{name}` אין ערך בררת מחדל"
default_not_match_type: "סוג ערך בררת המחדל של ההגדרה `%{name}` אינו תואם לסוג ההגדרה."

View File

@ -84,7 +84,7 @@ hr:
optimized_link: Optimizirane veze na slike su prolazne i ne bi trebale biti uključene u izvorni kod teme.
settings_errors:
invalid_yaml: "Zadani YAML je nevažeći"
data_type_not_a_number: "Vrsta postavke `%{name}` nije podržana. Podržane vrste su `integer`, `bool`, `list`, `enum` i `upload`"
data_type_inclusion: "Vrsta postavke `%{name}` nije podržana. Podržane vrste su `integer`, `bool`, `list`, `enum` i `upload`"
name_too_long: "Postoji postavka s predugim imenom. Najveća dopuštena duljina je 255"
default_value_missing: "Postavka `%{name}` nema podrazumijevanu vrijednost."
default_not_match_type: "Tip zadane vrijednosti postavke `%{name}` ne podudara se s postavljenom vrijednošću postavke."

View File

@ -81,7 +81,7 @@ hu:
no_multilevels_components: "A gyermektémákat tartalmazó témák nem lehet maguk is gyermektémák"
settings_errors:
invalid_yaml: "A megadott YAML érvénytelen."
data_type_not_a_number: "A `%{name}` típus beállítása nem támogatott. Támogatott típusok: `integer`, `bool`, `list`, `enum` és `upload`."
data_type_inclusion: "A `%{name}` típus beállítása nem támogatott. Támogatott típusok: `integer`, `bool`, `list`, `enum` és `upload`."
name_too_long: "Az egyik beállítás neve túl hosszú. A legnagyobb hossz 255"
default_value_missing: "A(z) „%{name}” beállításnak nincs alapértelmezett értéke."
default_not_match_type: "A(z) „%{name}” beállítás alapértelmezett értékének típusa nem egyezik a beállítás típusával."

View File

@ -93,7 +93,7 @@ id:
optimized_link: Tautan gambar yang dioptimalkan bersifat sementara dan tidak boleh disertakan dalam kode sumber tema.
settings_errors:
invalid_yaml: "YAML yang diberikan tidak valid."
data_type_not_a_number: "Pengaturan jenis `%{name}` tidak didukung. Jenis yang didukung adalah `integer`, `bool`, `list`, `enum` dan `upload`"
data_type_inclusion: "Pengaturan jenis `%{name}` tidak didukung. Jenis yang didukung adalah `integer`, `bool`, `list`, `enum` dan `upload`"
name_too_long: "Ada pengaturan dengan nama yang terlalu panjang. Panjang maksimum adalah 255"
default_value_missing: "Pengaturan `%{name}` tidak memiliki nilai bawaan"
default_not_match_type: "Pengaturan jenis nilai bawaan `%{name}` tidak cocok dengan jenis pengaturan."

View File

@ -110,7 +110,7 @@ it:
optimized_link: I collegamenti ad immagini ottimizzate sono effimeri e non devono essere inclusi nel codice sorgente del tema.
settings_errors:
invalid_yaml: "Il codice YAML fornito non è valido."
data_type_not_a_number: "L'impostazione del tipo `%{name}` non è supportata. I tipi supportati sono `integer`,` bool`, `list`,` enum` e `upload`"
data_type_inclusion: "L'impostazione del tipo `%{name}` non è supportata. I tipi supportati sono `integer`,` bool`, `list`,` enum` e `upload`"
name_too_long: "Una delle impostazioni ha un nome troppo lungo. La lunghezza massima è 255 caratteri"
default_value_missing: "L'impostazione `%{name}` non ha alcun valore predefinito"
default_not_match_type: "L'impostazione del valore predefinito `%{name}` non corrisponde al tipo di impostazione."

View File

@ -109,7 +109,7 @@ ja:
optimized_link: 最適化された画像のリンクは一時的なリンクであるため、テーマのソースコードに含めるべきではありません。
settings_errors:
invalid_yaml: "入力された YAML は無効です。"
data_type_not_a_number: "設定 `%{name}` の型はサポートされていません。サポートされている型は `integer`、`bool`、`list`、`enum`、`upload` です"
data_type_inclusion: "設定 `%{name}` の型はサポートされていません。サポートされている型は `integer`、`bool`、`list`、`enum`、`upload` です"
name_too_long: "名前が長すぎる設定があります。最大長は 255 です"
default_value_missing: "設定 `%{name}` にデフォルト値がありません"
default_not_match_type: "設定 `%{name}` のデフォルト値の型が設定の型に一致していません。"

View File

@ -81,7 +81,7 @@ ko:
optimized_link: 최적화된 이미지 링크는 일시적이므로 테마 소스 코드에 포함하지 않아야 합니다.
settings_errors:
invalid_yaml: "제공된 YAML이 유효하지 않습니다."
data_type_not_a_number: "`%{name}` 유형 설정은 지원되지 않습니다. 지원되는 유형은 `integer` , `bool` , `list` , `enum` 및 `upload` 입니다."
data_type_inclusion: "`%{name}` 유형 설정은 지원되지 않습니다. 지원되는 유형은 `integer` , `bool` , `list` , `enum` 및 `upload` 입니다."
name_too_long: "이름이 너무 긴 설정이 있습니다. 최대 길이는 255입니다"
default_value_missing: "`%{name}` 설정에 디폴트값이 없습니다"
default_not_match_type: "`%{name}` 디폴트값 유형 설정이 설정 유형과 일치하지 않습니다."

View File

@ -81,7 +81,7 @@ lt:
optimized_link: Optimizuotos vaizdo nuorodos yra trumpalaikės ir neturėtų būti įtrauktos į temos šaltinio kodą.
settings_errors:
invalid_yaml: "Nurodytas YAML negalimas."
data_type_not_a_number: "“%{name}” tipo nustatymas nepalaikomas. Palaikomi tipai yra `integer`, `bool`, `list`, `enum` ir `upload`"
data_type_inclusion: "“%{name}” tipo nustatymas nepalaikomas. Palaikomi tipai yra `integer`, `bool`, `list`, `enum` ir `upload`"
name_too_long: "Yra nustatymas su per ilgu pavadinimu. Maksimalus ilgis yra 255"
default_value_missing: "Nustatymas „%{name}“ neturi numatytosios vertės"
default_not_match_type: "Nustatymas „%{name}“ numatytosios vertės tipas neatitinka nustatymo tipo."

View File

@ -110,7 +110,7 @@ nl:
optimized_link: Geoptimaliseerde afbeeldingskoppelingen zijn kortstondig en dienen niet in broncode van thema's te worden opgenomen.
settings_errors:
invalid_yaml: "Opgegeven YAML is ongeldig."
data_type_not_a_number: "Type van instelling `%{name}` wordt niet ondersteund. Ondersteunde typen zijn `integer`, `bool`, `list`, `enum` en `upload`."
data_type_inclusion: "Type van instelling `%{name}` wordt niet ondersteund. Ondersteunde typen zijn `integer`, `bool`, `list`, `enum` en `upload`."
name_too_long: "Er is een instelling met een te lange naam. Maximale lengte is 255."
default_value_missing: "Instelling `%{name}` heeft geen standaardwaarde."
default_not_match_type: "Type van standaardwaarde van instelling `%{name}` komt niet overeen met het type van de instelling."

View File

@ -112,7 +112,7 @@ pl_PL:
optimized_link: Zoptymalizowane łącza do obrazów są efemeryczne i nie powinny być zawarte w kodzie źródłowym motywu.
settings_errors:
invalid_yaml: "Wprowadzony YAML jest nieprawidłowy"
data_type_not_a_number: "Ustawienie typu `%{name}` nie jest obsługiwane. Poprawne typy to `integer`, `bool`, `list`, `enum` oraz `upload`"
data_type_inclusion: "Ustawienie typu `%{name}` nie jest obsługiwane. Poprawne typy to `integer`, `bool`, `list`, `enum` oraz `upload`"
name_too_long: "Jedno z ustawień ma zbyt długą nazwę. Maksymalna długość to 255 znaków"
default_value_missing: "Ustawienie `%{name}` nie ma domyślnej wartości"
default_not_match_type: "Typ domyślnej wartości ustawienia \"%{name}\" nie odpowiada typowi ustawienia."

View File

@ -80,7 +80,7 @@ pt:
optimized_link: Os links de imagens otimizadas são efémeros e não devem ser incluídos no código-fonte do tema.
settings_errors:
invalid_yaml: "O YAML fornecido é inválido"
data_type_not_a_number: "A opção `%{name}` tipo não é suportada. Os tipos suportados são `integer`, `bool`, `list`, `enum` e `upload`"
data_type_inclusion: "A opção `%{name}` tipo não é suportada. Os tipos suportados são `integer`, `bool`, `list`, `enum` e `upload`"
name_too_long: "Existe uma configuração com um nome demasiado longo. O tamanho máximo é 255"
default_value_missing: "A configuração `%{name}` não tem um valor predefinido"
default_not_match_type: "O tipo do valor predefinido para a configuração `%{name}` não é igual ao esperado pela configuração."

View File

@ -110,7 +110,7 @@ pt_BR:
optimized_link: Links otimizados de imagem são temporários e não devem ser incluídos no código-fonte do tema.
settings_errors:
invalid_yaml: "O YAML informado é inválido."
data_type_not_a_number: "A configuração do tipo \"%{name}\" não é compatível. Os tipos compatíveis são \"integer\", \"bool\", \"list\", \"enum\" e \"upload\""
data_type_inclusion: "A configuração do tipo \"%{name}\" não é compatível. Os tipos compatíveis são \"integer\", \"bool\", \"list\", \"enum\" e \"upload\""
name_too_long: "Esta é uma configuração com um nome muito longo. O comprimento máximo é de 255"
default_value_missing: "A configuração \"%{name}\" não tem valor padrão"
default_not_match_type: "O tipo de valor padrão da configuração \"%{name}\" não corresponde ao tipo de configuração."

View File

@ -112,7 +112,7 @@ ru:
optimized_link: Оптимизированные ссылки на изображения являются эфемерными и не должны включаться в исходный код темы.
settings_errors:
invalid_yaml: "Неверный формат YAML-файла."
data_type_not_a_number: "Тип `%{name}` не поддерживается. Поддерживаются следующие типы: `integer`, `bool`, `list`, `enum` и `upload`."
data_type_inclusion: "Тип `%{name}` не поддерживается. Поддерживаются следующие типы: `integer`, `bool`, `list`, `enum` и `upload`."
name_too_long: "Есть настройка со слишком длинным названием. Максимальная длина — 255 символов."
default_value_missing: "Настройка `%{name}` не имеет значения по умолчанию"
default_not_match_type: "Стандартные значения настройки `%{name}` не соответствуют допустимым типам."

View File

@ -110,7 +110,7 @@ sv:
optimized_link: Optimerade bildlänkar är flyktiga och bör inte inkluderas i temakällkoden.
settings_errors:
invalid_yaml: "Angivet YAML är ogiltigt."
data_type_not_a_number: "Det går inte att ställa in typen `%{name}`. Typer som stöds är `integer`, `bool`, `list` , `enum` och `upload`"
data_type_inclusion: "Det går inte att ställa in typen `%{name}`. Typer som stöds är `integer`, `bool`, `list` , `enum` och `upload`"
name_too_long: "En inställning har ett namn som är för långt. Maximal längd är 255"
default_value_missing: "Inställningen `%{name}` har inget standardvärde"
default_not_match_type: "Standardvärdestypen i inställningen `%{name}` överensstämmer inte med inställningstypen."

View File

@ -110,7 +110,7 @@ tr_TR:
optimized_link: Optimize edilmiş resim bağlantıları geçicidir ve tema kaynak koduna dahil edilmemelidir.
settings_errors:
invalid_yaml: "Sağlanan YAML geçersiz."
data_type_not_a_number: "\"%{name}\" türünün ayarlanması desteklenmiyor. Desteklenen türler şunlardır: \"integer\", \"bool\", \"list\", \"enum\" ve \"upload\""
data_type_inclusion: "\"%{name}\" türünün ayarlanması desteklenmiyor. Desteklenen türler şunlardır: \"integer\", \"bool\", \"list\", \"enum\" ve \"upload\""
name_too_long: "Adı çok uzun olan bir ayar var. Maksimum uzunluk 255'tir"
default_value_missing: "\"%{name}\" ayarının varsayılan değeri yok"
default_not_match_type: "\"%{name}\" ayarının varsayılan değerinin türü ayar türüyle eşleşmiyor."

View File

@ -112,7 +112,7 @@ uk:
optimized_link: Посилання на оптимізовані зображення є тимчасовими і не повинні включатись у сирці теми.
settings_errors:
invalid_yaml: "Наданий YAML пошкоджений."
data_type_not_a_number: "Налаштування типу \"%{name}\" не підтримується. Підтримувані типи: `integer`, `bool`, `list`, `enum` і `upload`"
data_type_inclusion: "Налаштування типу \"%{name}\" не підтримується. Підтримувані типи: `integer`, `bool`, `list`, `enum` і `upload`"
name_too_long: "У вас є параметр із занадто довгим імʼям. Максимальна довжина 255"
default_value_missing: "Параметр `%{name}` не має стандартного значення"
default_not_match_type: "Стандартне значення параметра `%{name}`, не збігається з типом параметра."

View File

@ -80,7 +80,7 @@ ur:
optimized_link: آپٹمائزڈ تصویری لنکس عارضی ہیں اور تھیم سورس کوڈ میں شامل نہیں ہونے چاہئیں۔
settings_errors:
invalid_yaml: "فراہم کردہ YAML غلط ہے۔"
data_type_not_a_number: "`%{name}` قسم کی ترتیب غیر تعاون یافتہ ہے۔ تائید شدہ اقسام ہیں `انٹیجر`، `بول`، `لسٹ`، `اینم` اور `اپ لوڈ`"
data_type_inclusion: "`%{name}` قسم کی ترتیب غیر تعاون یافتہ ہے۔ تائید شدہ اقسام ہیں `انٹیجر`، `بول`، `لسٹ`، `اینم` اور `اپ لوڈ`"
name_too_long: "بہت طویل نام کے ساتھ ایک ترتیب موجود ہے۔ زیادہ سے زیادہ لمبائی 255 ہے"
default_value_missing: "ترتیب `%{name}` کی کوئی ڈِیفالٹ قدر نہیں ہے"
default_not_match_type: "ترتیب `%{name}` کی ڈِیفالٹ قدر کی قِسم، ترتیب قِسم سے مَیچ نہیں کرتی۔"

View File

@ -81,7 +81,7 @@ vi:
optimized_link: Các liên kết hình ảnh được tối ưu hóa là không lâu và không nên được bao gồm trong mã nguồn theme.
settings_errors:
invalid_yaml: "YAML được cung cấp không hợp lệ."
data_type_not_a_number: "Thiết lập kiểu `%{name}` không được hỗ trợ. Các kiểu được hỗ trợ là `integer`, `bool`, `list`, `enum` và `upload`"
data_type_inclusion: "Thiết lập kiểu `%{name}` không được hỗ trợ. Các kiểu được hỗ trợ là `integer`, `bool`, `list`, `enum` và `upload`"
name_too_long: "Có một cài đặt có tên quá dài. Chiều dài tối đa là 255"
default_value_missing: "Cài đặt `%{name}'không có giá trị mặc định"
default_not_match_type: "Đặt kiểu giá trị mặc định `%{name}` không khớp với kiểu cài đặt."

View File

@ -109,7 +109,7 @@ zh_CN:
optimized_link: 优化的图片链接是暂时的,不应包含在主题源代码中。
settings_errors:
invalid_yaml: "提供的 YAML 无效。"
data_type_not_a_number: "设置 `%{name}` 的类型不受支持。支持的类型为 `integer`、`bool`、`list` 、`enum` 和 `upload`"
data_type_inclusion: "设置 `%{name}` 的类型不受支持。支持的类型为 `integer`、`bool`、`list` 、`enum` 和 `upload`"
name_too_long: "有一个设置的名称过长。最大长度为 255"
default_value_missing: "设置 `%{name}` 无默认值"
default_not_match_type: "设置 `%{name}` 默认值的类型与设置类型不匹配。"

View File

@ -2357,6 +2357,9 @@ developer:
list_type: compact
allow_any: false
refresh: true
experimental_objects_type_for_theme_settings:
default: false
hidden: true
navigation:
navigation_menu:

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddJsonValueToThemeSettings < ActiveRecord::Migration[7.0]
def change
add_column :theme_settings, :json_value, :jsonb
end
end

View File

@ -113,6 +113,21 @@ class ThemeSettingsManager
(max.is_a?(::Integer) || max.is_a?(::Float)) && max != ::Float::INFINITY
end
class Objects < self
def value
has_record? ? db_record.json_value : default.map!(&:deep_stringify_keys)
end
def value=(objects)
# TODO: Validate the objects against the schema
record = has_record? ? db_record : create_record!
record.json_value = objects
record.save!
record.json_value
end
end
class List < self
def list_type
@opts[:list_type]

View File

@ -41,6 +41,7 @@ class ThemeSettingsParser
opts[:textarea] = !!raw_opts[:textarea]
opts[:json_schema] = raw_opts[:json_schema]
opts[:schema] = raw_opts[:schema]
opts[:refresh] = !!raw_opts[:refresh]

View File

@ -84,3 +84,16 @@ valid_json_schema_setting:
causes_refresh:
default: ""
refresh: true
valid_objects_setting:
type: objects
default:
- title: "Some title"
description: "Some description"
schema:
name: "Some Object"
fields:
title:
type: string
description:
type: string

View File

@ -12,6 +12,8 @@ RSpec.describe ThemeSettingsManager do
theme.settings
end
before { SiteSetting.experimental_objects_type_for_theme_settings = true }
describe "Enum" do
it "only accepts values from its choices" do
enum_setting = theme_settings[:enum_setting]
@ -184,4 +186,21 @@ RSpec.describe ThemeSettingsManager do
end
end
end
describe ThemeSettingsManager::Objects do
it "can store a list of objects" do
objects_setting = theme_settings[:valid_objects_setting]
expect(objects_setting.value).to eq(
[{ "title" => "Some title", "description" => "Some description" }],
)
objects_setting.value = [{ title: "title 1", description: "description 1" }]
objects_setting = theme.reload.settings[:valid_objects_setting]
expect(objects_setting.value).to eq(
[{ "title" => "title 1", "description" => "description 1" }],
)
end
end
end

View File

@ -7,6 +7,7 @@ RSpec.describe ThemeField do
before do
SvgSprite.clear_plugin_svg_sprite_cache!
ThemeJavascriptCompiler.disable_terser!
SiteSetting.experimental_objects_type_for_theme_settings = true
end
after { ThemeJavascriptCompiler.enable_terser! }
@ -385,7 +386,7 @@ HTML
it "generates errors when invalid type is passed" do
field = create_yaml_field(get_fixture("invalid"))
expect(field.error).to include(
I18n.t("#{key}.data_type_not_a_number", name: "invalid_type_setting"),
I18n.t("#{key}.data_type_inclusion", name: "invalid_type_setting"),
)
end

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
RSpec.describe ThemeSetting do
fab!(:theme)
context "for validations" do
it "should be invalid when setting data_type to objects and `experimental_objects_type_for_theme_settings` is disabled" do
SiteSetting.experimental_objects_type_for_theme_settings = false
theme_setting =
ThemeSetting.new(name: "test", data_type: ThemeSetting.types[:objects], theme:)
expect(theme_setting.valid?).to eq(false)
expect(theme_setting.errors[:data_type]).to contain_exactly("is not included in the list")
end
it "should be valid when setting data_type to objects and `experimental_objects_type_for_theme_settings` is enabled" do
SiteSetting.experimental_objects_type_for_theme_settings = true
theme_setting =
ThemeSetting.new(name: "test", data_type: ThemeSetting.types[:objects], theme:)
expect(theme_setting.valid?).to eq(true)
end
end
end