mirror of
https://github.com/discourse/discourse.git
synced 2026-08-06 03:07:17 -05:00
DEV: migrate from Advanced Search banner to Welcome banner (#34534)
1. Changes translation to a more meaningful: `welcome_banner.search` => `welcome_banner.search_placeholder`. * and passes along translation key, rather then `i18n` helper in `<SearchMenu>` - to make translation handling more consistent 2. Transitions communities from the **Advanced Search Banner** (ASB) theme component to the **core welcome banner** (CWB). It handles the transition in three major steps: * migrates site settings: task "themes:advanced_search_banner:migrate_settings_to_welcome_banner" * migrates translations: task "themes:advanced_search_banner:migrate_translations_to_welcome_banner" * excludes ASB from themes using it, enables CWB, disables ASB: task "themes:advanced_search_banner:exclude_and_disable" ### Settings migration 1. Happy path <img width="1029" height="192" alt="Screenshot 2025-10-29 at 12 40 51" src="https://github.com/user-attachments/assets/5d29ef48-ce60-4222-b32a-217390967b8d" /> ### Translations migration 1. Migrates overridden and default texts <img width="1062" height="291" alt="Screenshot 2025-10-29 at 12 44 26" src="https://github.com/user-attachments/assets/c43d51a4-59f8-4751-8abb-ae8824a7100f" /> ### Exclude ASB, enable CWB, disable ASB 2. When ASB is not included in any of themes, all migrations are skipped, except for disabling ASB <img width="807" height="458" alt="Screenshot 2025-10-30 at 11 48 43" src="https://github.com/user-attachments/assets/34e7bd5f-b334-4833-89a1-00d02faac23b" />
This commit is contained in:
@@ -324,7 +324,7 @@ en:
|
||||
subheader:
|
||||
logged_in_members: ""
|
||||
anonymous_members: ""
|
||||
search: "Search"
|
||||
search_placeholder: "Search"
|
||||
|
||||
impersonation:
|
||||
notice: "You are impersonating %{username}"
|
||||
|
||||
@@ -52,6 +52,7 @@ export default class SearchMenu extends Component {
|
||||
@tracked menuPanelOpen = false;
|
||||
|
||||
searchInputId = this.args.searchInputId ?? "search-term";
|
||||
searchInputPlaceholder = this.args.searchInputPlaceholder || "search.title";
|
||||
|
||||
_debouncer = null;
|
||||
_activeSearch = null;
|
||||
@@ -454,7 +455,7 @@ export default class SearchMenu extends Component {
|
||||
@openSearchMenu={{this.open}}
|
||||
@autofocus={{@autofocusInput}}
|
||||
@inputId={{this.searchInputId}}
|
||||
@placeholder={{@placeholder}}
|
||||
@inputPlaceholder={{this.searchInputPlaceholder}}
|
||||
/>
|
||||
|
||||
{{#if this.loading}}
|
||||
|
||||
@@ -121,8 +121,8 @@ export default class SearchTerm extends Component {
|
||||
autocomplete="off"
|
||||
enterkeyhint="search"
|
||||
value={{this.search.activeGlobalSearchTerm}}
|
||||
placeholder={{this.placeholderText}}
|
||||
aria-label={{this.placeholderText}}
|
||||
placeholder={{i18n @inputPlaceholder}}
|
||||
aria-label={{i18n @inputPlaceholder}}
|
||||
{{on "keyup" this.onKeyup}}
|
||||
{{on "keydown" this.onKeydown}}
|
||||
{{on "input" this.updateSearchTerm}}
|
||||
|
||||
@@ -189,7 +189,7 @@ export default class WelcomeBanner extends Component {
|
||||
<SearchMenu
|
||||
@location="welcome-banner"
|
||||
@searchInputId="welcome-banner-search-input"
|
||||
@placeholder={{i18n "welcome_banner.search"}}
|
||||
@searchInputPlaceholder="welcome_banner.search_placeholder"
|
||||
/>
|
||||
</div>
|
||||
<PluginOutlet @name="welcome-banner-below-input" />
|
||||
|
||||
@@ -61,15 +61,15 @@ module(
|
||||
assert.dom(".welcome-banner .welcome-banner__title input").doesNotExist();
|
||||
});
|
||||
|
||||
test("uses the welcome_banner.search translation for placeholder", async function (assert) {
|
||||
test("uses the welcome_banner.search_placeholder translation for placeholder", async function (assert) {
|
||||
await render(<template><WelcomeBanner /></template>);
|
||||
|
||||
assert
|
||||
.dom("#welcome-banner-search-input")
|
||||
.hasAttribute(
|
||||
"placeholder",
|
||||
i18n("welcome_banner.search"),
|
||||
"search input uses the welcome_banner.search translation as placeholder"
|
||||
i18n("welcome_banner.search_placeholder"),
|
||||
"search input uses the welcome_banner.search_placeholder translation as placeholder"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
THEME_GIT_URL = "https://github.com/discourse/discourse-search-banner.git" unless defined?(
|
||||
THEME_GIT_URL
|
||||
)
|
||||
REQUIRED_TRANSLATION_KEYS = %w[search_banner.headline search_banner.subhead] unless defined?(
|
||||
REQUIRED_TRANSLATION_KEYS
|
||||
)
|
||||
|
||||
desc "Migrate settings from Advanced Search Banner to core welcome banner"
|
||||
task "themes:advanced_search_banner:migrate_settings_to_welcome_banner" => :environment do
|
||||
components = find_all_components([:theme_settings])
|
||||
|
||||
if components.empty?
|
||||
puts "\n\e[33m✗ No Advanced Search Banner theme components found\e[0m"
|
||||
next
|
||||
end
|
||||
|
||||
components.each { |entry| process_theme_component_settings(entry[:theme]) }
|
||||
end
|
||||
|
||||
desc "Migrate translations from Advanced Search Banner to core welcome banner"
|
||||
task "themes:advanced_search_banner:migrate_translations_to_welcome_banner" => :environment do
|
||||
components = find_all_components([:theme_translation_overrides])
|
||||
|
||||
if components.empty?
|
||||
puts "\n\e[33m✗ No Advanced Search Banner theme components found\e[0m"
|
||||
next
|
||||
end
|
||||
|
||||
components.each { |entry| process_theme_component_translations(entry[:theme]) }
|
||||
end
|
||||
|
||||
desc "Exclude and disable Advanced Search Banner theme component"
|
||||
task "themes:advanced_search_banner:exclude_and_disable" => :environment do
|
||||
components = find_all_components
|
||||
|
||||
if components.empty?
|
||||
puts "\n\e[33m✗ No Advanced Search Banner theme components found\e[0m"
|
||||
next
|
||||
end
|
||||
|
||||
components.each { |entry| process_theme_component(entry[:theme]) }
|
||||
end
|
||||
|
||||
# Common helper methods
|
||||
def find_all_components(includes = [])
|
||||
if ENV["RAILS_DB"].present?
|
||||
db = validate_and_get_db(ENV["RAILS_DB"])
|
||||
RailsMultisite::ConnectionManagement.establish_connection(db: db)
|
||||
wrap_themes_with_db(find_components_in_db(db, includes), db)
|
||||
else
|
||||
components = []
|
||||
RailsMultisite::ConnectionManagement.each_connection do |db|
|
||||
components.concat(wrap_themes_with_db(find_components_in_db(db, includes), db))
|
||||
end
|
||||
components
|
||||
end
|
||||
end
|
||||
|
||||
def validate_and_get_db(db)
|
||||
return db if RailsMultisite::ConnectionManagement.has_db?(db)
|
||||
|
||||
default_db = RailsMultisite::ConnectionManagement::DEFAULT
|
||||
puts "\e[31m✗ Database \e[1;101m[#{db}]\e[0m \e[31mnot found\e[0m"
|
||||
puts "Using default database instead: \e[1;104m[#{default_db}]\e[0m\n\n"
|
||||
default_db
|
||||
end
|
||||
|
||||
def wrap_themes_with_db(themes, db)
|
||||
themes.map { |theme| { db: db, theme: theme } }
|
||||
end
|
||||
|
||||
def find_components_in_db(db, additional_includes)
|
||||
puts "Accessing database: \e[1;104m[#{db}]\e[0m"
|
||||
puts " Searching for Advanced Search Banner components..."
|
||||
|
||||
includes = [{ parent_theme_relation: :parent_theme }] + Array(additional_includes)
|
||||
themes = RemoteTheme.where(remote_url: THEME_GIT_URL).includes(theme: includes).map(&:theme)
|
||||
|
||||
themes.each { |theme| puts " \e[1;34mFound: #{theme_identifier(theme)}" }
|
||||
themes
|
||||
end
|
||||
|
||||
def theme_identifier(theme)
|
||||
"\e[1m#{theme.name} (ID: #{theme.id})\e[0m"
|
||||
end
|
||||
|
||||
def not_included_in_any_theme?(theme)
|
||||
return false if theme.parent_theme_relation.exists?
|
||||
|
||||
puts " \e[33m#{theme_identifier(theme)} is not included in any of your themes. Skipping\e[0m"
|
||||
true
|
||||
end
|
||||
|
||||
# Settings migration methods
|
||||
unless defined?(SETTINGS_MAPPING)
|
||||
SETTINGS_MAPPING = {
|
||||
"show_on" => {
|
||||
site_setting: "welcome_banner_page_visibility",
|
||||
value_mapping: {
|
||||
"top_menu" => "top_menu_pages",
|
||||
"all" => "all_pages",
|
||||
},
|
||||
},
|
||||
"plugin_outlet" => {
|
||||
site_setting: "welcome_banner_location",
|
||||
value_mapping: {
|
||||
"above-main-container" => "above_topic_content",
|
||||
"below-site-header" => "below_site_header",
|
||||
},
|
||||
},
|
||||
"background_image_light" => {
|
||||
site_setting: "welcome_banner_image",
|
||||
value_mapping: nil,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
def process_theme_component_settings(theme)
|
||||
return if not_included_in_any_theme?(theme)
|
||||
migration_errors = []
|
||||
|
||||
puts "\n Migrating settings for #{theme_identifier(theme)}..."
|
||||
migrated_count = migrate_theme_settings_to_site_settings(theme.theme_settings, migration_errors)
|
||||
if migrated_count == theme.theme_settings.size
|
||||
puts " \e[1;32m✓ Migrated #{migrated_count} setting#{"s" if migrated_count != 1}\e[0m"
|
||||
else
|
||||
puts " \e[33mMigrated #{migrated_count} out of #{theme.theme_settings.size} setting#{"s" if theme.theme_settings.size != 1}\e[0m"
|
||||
end
|
||||
|
||||
if migration_errors.any?
|
||||
puts "\n\e[1;31mMigration completed with errors\e[0m"
|
||||
else
|
||||
puts "\n\e[1;34mMigration completed successfully!\e[0m"
|
||||
end
|
||||
end
|
||||
|
||||
def migrate_theme_settings_to_site_settings(theme_settings, errors)
|
||||
migrated_count = 0
|
||||
|
||||
theme_settings.each do |ts|
|
||||
mapping = SETTINGS_MAPPING[ts.name]
|
||||
next unless mapping
|
||||
|
||||
site_setting_name = mapping[:site_setting]
|
||||
if ts.value.blank?
|
||||
puts " - skipping '#{ts.name}' as it has no value"
|
||||
next
|
||||
end
|
||||
|
||||
if mapping[:value_mapping]
|
||||
new_value = mapping[:value_mapping][ts.value] || ts.value
|
||||
else
|
||||
new_value = ts.value.to_i
|
||||
end
|
||||
|
||||
begin
|
||||
SiteSetting.set_and_log(
|
||||
site_setting_name,
|
||||
new_value,
|
||||
Discourse.system_user,
|
||||
"Migrated from the deprecated Advanced Search Banner",
|
||||
)
|
||||
|
||||
old_text = "\e[0;31m#{ts.name}: #{ts.value}\e[0m"
|
||||
arrow = "\e[0m=>\e[0m"
|
||||
new_text = "\e[0;32m#{site_setting_name}: #{new_value}\e[0m"
|
||||
|
||||
puts " - #{old_text} #{arrow} #{new_text}"
|
||||
migrated_count += 1
|
||||
rescue StandardError => e
|
||||
errors << e
|
||||
puts " \e[31m- failed to migrate '#{ts.name}': \e[1m#{e.message}\e[0m"
|
||||
end
|
||||
end
|
||||
|
||||
migrated_count
|
||||
end
|
||||
|
||||
# Translations migration methods
|
||||
def process_theme_component_translations(theme)
|
||||
return if not_included_in_any_theme?(theme)
|
||||
|
||||
puts "\n Migrating translation overrides for #{theme_identifier(theme)}..."
|
||||
|
||||
migrated_count = 0
|
||||
|
||||
if theme.theme_translation_overrides.any?
|
||||
processed_keys_by_locale = Hash.new { |h, k| h[k] = Set.new }
|
||||
|
||||
theme.theme_translation_overrides.each do |override|
|
||||
count =
|
||||
migrate_translations(
|
||||
locale: override.locale,
|
||||
key: override.translation_key,
|
||||
value: override.value,
|
||||
)
|
||||
migrated_count += count
|
||||
|
||||
processed_keys_by_locale[override.locale].add(override.translation_key)
|
||||
end
|
||||
|
||||
shown = false
|
||||
processed_keys_by_locale.each do |locale, processed_keys|
|
||||
missing_keys = REQUIRED_TRANSLATION_KEYS - processed_keys.to_a
|
||||
|
||||
if missing_keys.any?
|
||||
unless shown
|
||||
puts " Migrating Advanced Search Banner's default translations..."
|
||||
shown = true
|
||||
end
|
||||
|
||||
missing_keys.each do |missing_key|
|
||||
count = migrate_translations(locale: locale, key: missing_key)
|
||||
migrated_count += count
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
puts " \e[33m✗ No translation overrides found\e[0m"
|
||||
puts " Migrating Advanced Search Banner's default translations..."
|
||||
REQUIRED_TRANSLATION_KEYS.each do |required_key|
|
||||
count = migrate_translations(key: required_key)
|
||||
migrated_count += count
|
||||
end
|
||||
end
|
||||
|
||||
puts " \e[1;32m✓ Migrated #{migrated_count} translation#{"s" if migrated_count != 1}\e[0m"
|
||||
puts "\n\e[1;34mMigration completed successfully!\e[0m"
|
||||
end
|
||||
|
||||
def migrate_translations(locale: "en", key:, value: nil)
|
||||
default_translations = {
|
||||
"js.welcome_banner.header.anonymous_members" => "Welcome to our community",
|
||||
"js.welcome_banner.header.logged_in_members" => "Welcome to our community",
|
||||
"js.welcome_banner.subheader.anonymous_members" =>
|
||||
"We're happy to have you here. If you need help, please search before you post.",
|
||||
"js.welcome_banner.subheader.logged_in_members" =>
|
||||
"We're happy to have you here. If you need help, please search before you post.",
|
||||
}
|
||||
mapped_keys = map_translation_keys(key)
|
||||
|
||||
# Print the value once before processing all keys
|
||||
first_key = mapped_keys.first
|
||||
new_value = value || default_translations[first_key]
|
||||
puts " \e[1;32m✓\e[0m \e[1;94m\"#{new_value}\"\e[0m"
|
||||
|
||||
mapped_keys.each do |new_key|
|
||||
actual_value = value || default_translations[new_key]
|
||||
TranslationOverride.upsert!(locale, new_key, actual_value)
|
||||
|
||||
old_text = "\e[0;31m#{key}\e[0m"
|
||||
arrow = "\e[0m=>\e[0m"
|
||||
new_text = "\e[0;32m#{locale}.#{new_key}\e[0m"
|
||||
|
||||
puts " - #{old_text} #{arrow} #{new_text}"
|
||||
end
|
||||
|
||||
mapped_keys.count
|
||||
end
|
||||
|
||||
def map_translation_keys(translation_key)
|
||||
translations_mapping = {
|
||||
"search_banner.headline" => %w[
|
||||
js.welcome_banner.header.anonymous_members
|
||||
js.welcome_banner.header.logged_in_members
|
||||
],
|
||||
"search_banner.subhead" => %w[
|
||||
js.welcome_banner.subheader.anonymous_members
|
||||
js.welcome_banner.subheader.logged_in_members
|
||||
],
|
||||
"search_banner.search_button_text" => ["js.welcome_banner.search_placeholder"],
|
||||
}
|
||||
|
||||
translations_mapping[translation_key] || []
|
||||
end
|
||||
|
||||
# Exclude and disable methods
|
||||
def process_theme_component(theme)
|
||||
exclude_theme_component(theme)
|
||||
enable_welcome_banner(theme)
|
||||
disable_theme_component(theme)
|
||||
|
||||
puts "\n\e[1;34mTask completed successfully!\e[0m"
|
||||
end
|
||||
|
||||
def exclude_theme_component(theme)
|
||||
puts "\n Executing exclude step..."
|
||||
return if not_included_in_any_theme?(theme)
|
||||
|
||||
parent_relations = theme.parent_theme_relation.to_a
|
||||
total_relations = parent_relations.size
|
||||
|
||||
puts "\n Excluding #{theme_identifier(theme)} from..."
|
||||
parent_relations.each do |relation|
|
||||
puts " - #{relation.parent_theme.name} (ID: #{relation.parent_theme_id})"
|
||||
relation.destroy!
|
||||
end
|
||||
puts " \e[1;32m✓ Excluded from #{total_relations} theme#{"s" if total_relations > 1}\e[0m"
|
||||
end
|
||||
|
||||
def enable_welcome_banner(theme)
|
||||
puts "\n Executing enable core welcome banner step..."
|
||||
if !theme.enabled
|
||||
puts " \e[33m#{theme_identifier(theme)} is disabled, thus no need to enable core welcome banner. Skipping\e[0m"
|
||||
return
|
||||
end
|
||||
return unless theme.enabled
|
||||
|
||||
return if not_included_in_any_theme?(theme)
|
||||
|
||||
puts "\n Enabling \e[1mcore welcome banner\e[0m for..."
|
||||
enabled_count = 0
|
||||
|
||||
theme.parent_theme_relation.each do |relation|
|
||||
parent_theme = relation.parent_theme
|
||||
site_setting =
|
||||
ThemeSiteSetting.find_by(theme_id: parent_theme.id, name: "enable_welcome_banner")
|
||||
|
||||
if site_setting.value == "f"
|
||||
site_setting.update!(value: "t")
|
||||
puts " - #{parent_theme.name} (ID: #{parent_theme.id}) \e[32m- enabled\e[0m"
|
||||
enabled_count += 1
|
||||
else
|
||||
puts " - #{parent_theme.name} (ID: #{parent_theme.id}) \e[33m- it was already enabled. Skipping\e[0m"
|
||||
end
|
||||
end
|
||||
|
||||
puts " \e[1;32m✓ Enabled for #{enabled_count} theme#{"s" unless enabled_count == 1}\e[0m"
|
||||
end
|
||||
|
||||
def disable_theme_component(theme)
|
||||
puts "\n Executing disable component step..."
|
||||
if !theme.enabled
|
||||
puts " \e[33m#{theme_identifier(theme)} was already disabled. Skipping\e[0m"
|
||||
return
|
||||
end
|
||||
|
||||
puts "\n Disabling #{theme_identifier(theme)}..."
|
||||
theme.update!(enabled: false)
|
||||
puts " \e[1;32m✓ Disabled\e[0m"
|
||||
end
|
||||
@@ -0,0 +1,202 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe "tasks/migrate_advanced_search_banner_to_welcome_banner" do
|
||||
before do
|
||||
Rake::Task.clear
|
||||
load Rails.root.join("lib/tasks/migrate_advanced_search_banner_to_welcome_banner.rake")
|
||||
end
|
||||
|
||||
describe "#validate_and_get_db" do
|
||||
it "returns the database name if it exists" do
|
||||
db = "default"
|
||||
RailsMultisite::ConnectionManagement.stubs(:has_db?).with(db).returns(true)
|
||||
|
||||
result = validate_and_get_db(db)
|
||||
|
||||
expect(result).to eq(db)
|
||||
end
|
||||
|
||||
it "returns default database when provided database does not exist" do
|
||||
db = "nonexistent"
|
||||
default_db = RailsMultisite::ConnectionManagement::DEFAULT
|
||||
RailsMultisite::ConnectionManagement.stubs(:has_db?).with(db).returns(false)
|
||||
|
||||
result = validate_and_get_db(db)
|
||||
|
||||
expect(result).to eq(default_db)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#wrap_themes_with_db" do
|
||||
it "wraps themes with database information" do
|
||||
theme1 = Fabricate(:theme)
|
||||
theme2 = Fabricate(:theme)
|
||||
db = "default"
|
||||
|
||||
result = wrap_themes_with_db([theme1, theme2], db)
|
||||
|
||||
expect(result).to eq([{ db: db, theme: theme1 }, { db: db, theme: theme2 }])
|
||||
end
|
||||
|
||||
it "returns empty array when no themes provided" do
|
||||
result = wrap_themes_with_db([], "default")
|
||||
|
||||
expect(result).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
describe "#theme_identifier" do
|
||||
it "returns formatted theme identifier" do
|
||||
theme = Fabricate(:theme, name: "Test Theme")
|
||||
|
||||
result = theme_identifier(theme)
|
||||
|
||||
expect(result).to include("Test Theme")
|
||||
expect(result).to include(theme.id.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#not_included_in_any_theme?" do
|
||||
fab!(:parent_theme, :theme)
|
||||
fab!(:child_theme) { Fabricate(:theme, component: true) }
|
||||
|
||||
it "returns false when theme is included in a parent theme" do
|
||||
ChildTheme.create!(parent_theme: parent_theme, child_theme: child_theme)
|
||||
|
||||
expect(not_included_in_any_theme?(child_theme)).to eq(false)
|
||||
end
|
||||
|
||||
it "returns true and prints message when theme is not included in any parent theme" do
|
||||
orphan_theme = Fabricate(:theme, component: true)
|
||||
|
||||
expect {
|
||||
result = not_included_in_any_theme?(orphan_theme)
|
||||
expect(result).to eq(true)
|
||||
}.to output(/is not included in any of your themes/).to_stdout
|
||||
end
|
||||
end
|
||||
|
||||
describe "#map_translation_keys" do
|
||||
it "returns mapped keys for headline" do
|
||||
result = map_translation_keys("search_banner.headline")
|
||||
|
||||
expect(result).to eq(
|
||||
%w[js.welcome_banner.header.anonymous_members js.welcome_banner.header.logged_in_members],
|
||||
)
|
||||
end
|
||||
|
||||
it "returns mapped keys for subhead" do
|
||||
result = map_translation_keys("search_banner.subhead")
|
||||
|
||||
expect(result).to eq(
|
||||
%w[
|
||||
js.welcome_banner.subheader.anonymous_members
|
||||
js.welcome_banner.subheader.logged_in_members
|
||||
],
|
||||
)
|
||||
end
|
||||
|
||||
it "returns empty array for unknown translation key" do
|
||||
result = map_translation_keys("unknown.key")
|
||||
|
||||
expect(result).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
describe "SETTINGS_MAPPING" do
|
||||
it "maps show_on setting correctly" do
|
||||
expect(SETTINGS_MAPPING["show_on"][:site_setting]).to eq("welcome_banner_page_visibility")
|
||||
expect(SETTINGS_MAPPING["show_on"][:value_mapping]["top_menu"]).to eq("top_menu_pages")
|
||||
expect(SETTINGS_MAPPING["show_on"][:value_mapping]["all"]).to eq("all_pages")
|
||||
end
|
||||
|
||||
it "maps plugin_outlet setting correctly" do
|
||||
expect(SETTINGS_MAPPING["plugin_outlet"][:site_setting]).to eq("welcome_banner_location")
|
||||
expect(SETTINGS_MAPPING["plugin_outlet"][:value_mapping]["above-main-container"]).to eq(
|
||||
"above_topic_content",
|
||||
)
|
||||
expect(SETTINGS_MAPPING["plugin_outlet"][:value_mapping]["below-site-header"]).to eq(
|
||||
"below_site_header",
|
||||
)
|
||||
end
|
||||
|
||||
it "maps background_image_light setting correctly" do
|
||||
expect(SETTINGS_MAPPING["background_image_light"][:site_setting]).to eq(
|
||||
"welcome_banner_image",
|
||||
)
|
||||
expect(SETTINGS_MAPPING["background_image_light"][:value_mapping]).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "#exclude_theme_component" do
|
||||
fab!(:parent_theme, :theme)
|
||||
fab!(:child_theme) { Fabricate(:theme, component: true) }
|
||||
|
||||
it "excludes theme from parent themes when relations exist" do
|
||||
ChildTheme.create!(parent_theme: parent_theme, child_theme: child_theme)
|
||||
|
||||
expect { exclude_theme_component(child_theme) }.to output(/Excluding.*from/).to_stdout
|
||||
end
|
||||
|
||||
it "handles theme with no parent relations" do
|
||||
orphan_theme = Fabricate(:theme, component: true)
|
||||
|
||||
expect { exclude_theme_component(orphan_theme) }.to output(
|
||||
/is not included in any of your themes/,
|
||||
).to_stdout
|
||||
end
|
||||
end
|
||||
|
||||
describe "#disable_theme_component" do
|
||||
it "disables an enabled theme" do
|
||||
theme = Fabricate(:theme, enabled: true)
|
||||
|
||||
expect { disable_theme_component(theme) }.to output(/Disabled/).to_stdout
|
||||
expect(theme.reload.enabled).to eq(false)
|
||||
end
|
||||
|
||||
it "skips disabling an already disabled theme" do
|
||||
theme = Fabricate(:theme, enabled: false)
|
||||
|
||||
expect { disable_theme_component(theme) }.to output(/already disabled/).to_stdout
|
||||
expect(theme.reload.enabled).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#enable_welcome_banner" do
|
||||
fab!(:parent_theme, :theme)
|
||||
fab!(:child_theme) { Fabricate(:theme, component: true, enabled: true) }
|
||||
|
||||
before { ChildTheme.create!(parent_theme: parent_theme, child_theme: child_theme) }
|
||||
|
||||
it "enables welcome banner when theme is enabled and setting is false" do
|
||||
ThemeSiteSetting.create!(
|
||||
theme: parent_theme,
|
||||
name: "enable_welcome_banner",
|
||||
data_type: 5,
|
||||
value: "f",
|
||||
)
|
||||
|
||||
expect { enable_welcome_banner(child_theme) }.to output(/enabled/).to_stdout
|
||||
expect(
|
||||
ThemeSiteSetting.find_by(theme: parent_theme, name: "enable_welcome_banner").value,
|
||||
).to eq("t")
|
||||
end
|
||||
|
||||
it "does nothing when theme is disabled" do
|
||||
disabled_theme = Fabricate(:theme, component: true, enabled: false)
|
||||
|
||||
result = enable_welcome_banner(disabled_theme)
|
||||
|
||||
expect(result).to be_nil
|
||||
end
|
||||
|
||||
it "skips when theme has no parent relations" do
|
||||
orphan_theme = Fabricate(:theme, component: true, enabled: true)
|
||||
|
||||
result = enable_welcome_banner(orphan_theme)
|
||||
|
||||
expect(result).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user