0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-06 03:25:17 +08:00
discourse/lib/tasks/javascript.rake
Régis Hanol db1fb7ba91
UX: Explain invalid automatic membership email domains (#41233)
Previously, saving a group with a malformed automatic membership email
domain (such as one that includes `@`) failed with an opaque "FAILED"
popup that gave no indication of what was wrong or how to fix it.

This change surfaces the underlying validation error on save, warns
about and lists the offending domains before the save is attempted, and
adds an inline hint describing the expected format.

**Screenshots**

<img width="1400" height="1200"
alt="desktop-horizon-light-group-domain-field-hint"
src="https://github.com/user-attachments/assets/8fa08914-29bf-4afb-be02-666d5399b446"
/>

<img width="1400" height="1200"
alt="desktop-horizon-light-group-domain-invalid-warning"
src="https://github.com/user-attachments/assets/5372ac0b-f59d-4e09-89aa-3f3a53e3fba5"
/>
2026-07-02 16:52:16 +02:00

131 lines
5.1 KiB
Ruby
Vendored

# frozen_string_literal: true
def write_template(path, task_name, template)
header = <<~JS
// DO NOT EDIT THIS FILE!!!
// Update it by running `rake javascript:#{task_name}`
JS
basename = File.basename(path)
output_path = "#{Rails.root.join("frontend/#{path}")}"
File.write(output_path, "#{header}\n\n#{template}")
puts "#{basename} created"
system("pnpm prettier --write #{output_path}", exception: true)
puts "#{basename} prettified"
end
task "javascript:update_constants" => :environment do
task_name = "update_constants"
category_additional_assign_allowed_groups =
DiscourseAssign::AssignmentPermissions::CATEGORY_ADDITIONAL_ASSIGN_ALLOWED_GROUPS
auto_groups =
Group::AUTO_GROUPS.inject({}) do |result, (group_name, group_id)|
result.merge(group_name => { id: group_id, automatic: true, name: group_name })
end
MAIN_FONT_KEYS = %w[helvetica inter lato montserrat open_sans poppins roboto merriweather mukta]
write_template("discourse/admin/lib/constants.js", task_name, <<~JS)
export const ADMIN_SEARCH_RESULT_TYPES = #{Admin::SearchController::RESULT_TYPES.to_json};
export const SITE_SETTING_REQUIRES_CONFIRMATION_TYPES = #{SiteSettings::TypeSupervisor::REQUIRES_CONFIRMATION_TYPES.to_json};
export const API_KEY_SCOPE_MODES = #{ApiKey.scope_modes.keys.to_json}
export const SYSTEM_FLAG_IDS = #{PostActionType.types.to_json};
export const REPORT_MODES = #{Report::MODES.to_json};
export const USER_FIELD_FLAGS = #{UserField::FLAG_ATTRIBUTES};
export const DEFAULT_USER_PREFERENCES = #{SiteSetting::DEFAULT_USER_PREFERENCES.to_json};
export const MAIN_FONTS = #{DiscourseFonts.fonts.filter { |font| MAIN_FONT_KEYS.include?(font[:key]) }.map { |font| { key: font[:key], name: font[:name] } }.to_json}
export const MORE_FONTS = #{DiscourseFonts.fonts.reject { |font| MAIN_FONT_KEYS.include?(font[:key]) }.map { |font| { key: font[:key], name: font[:name] } }.to_json}
export const DEFAULT_TEXT_SIZES = #{DefaultTextSizeSetting::DEFAULT_TEXT_SIZES}
JS
write_template("discourse/app/lib/constants.js", task_name, <<~JS)
export const SEARCH_PRIORITIES = #{Searchable::PRIORITIES.to_json};
export const SEARCH_PHRASE_REGEXP = '#{Search::PHRASE_MATCH_REGEXP_PATTERN}';
export const SIDEBAR_URL = {
max_icon_length: #{SidebarUrl::MAX_ICON_LENGTH},
max_name_length: #{SidebarUrl::MAX_NAME_LENGTH},
max_value_length: #{SidebarUrl::MAX_VALUE_LENGTH}
}
export const SIDEBAR_SECTION = {
max_title_length: #{SidebarSection::MAX_TITLE_LENGTH},
}
export const CATEGORY_STYLE_TYPES = #{Category.style_types.to_json};
export const CATEGORY_TEXT_COLORS = #{Category::DEFAULT_TEXT_COLORS};
export const CATEGORY_ADDITIONAL_ASSIGN_ALLOWED_GROUPS = "#{category_additional_assign_allowed_groups}";
// NOTE: Group names are changed based on the site's locale, see
// Group.refresh_automatic_group! for more details
export const AUTO_GROUPS = #{auto_groups.to_json};
export const GROUP_SMTP_SSL_MODES = #{Group.smtp_ssl_modes.to_json};
export const GROUP_VISIBILITY_LEVELS = #{Group.visibility_levels.to_json};
export const MAX_NOTIFICATIONS_LIMIT_PARAMS = #{NotificationsController::INDEX_LIMIT};
export const TOPIC_VISIBILITY_REASONS = #{Topic.visibility_reasons.to_json};
export const MAX_UNOPTIMIZED_CATEGORIES = #{CategoryList::MAX_UNOPTIMIZED_CATEGORIES};
export const REVIEWABLE_UNKNOWN_TYPE_SOURCE = "#{Reviewable::UNKNOWN_TYPE_SOURCE}";
export const ADMIN_SEARCH_RESULT_TYPES = #{Admin::SearchController::RESULT_TYPES.to_json};
export const API_KEY_SCOPE_MODES = #{ApiKey.scope_modes.keys.to_json};
export const INVITE_DESCRIPTION_MAX_LENGTH = #{Invite::DESCRIPTION_MAX_LENGTH};
export const POSTING_REVIEW_GROUP_BASED_MODES = #{CategorySetting::GROUP_BASED_MODES.to_json};
export const USER_OPTION_COMPOSITION_MODES = #{UserOption.composition_mode_types.to_json};
export const UPCOMING_CHANGES_USER_ENABLED_REASONS = #{UpcomingChanges.user_enabled_reasons.to_json};
export const INTERFACE_COLOR_MODES = {
AUTO: #{UserOption::AUTO_MODE},
LIGHT: #{UserOption::LIGHT_MODE},
DARK: #{UserOption::DARK_MODE},
};
JS
pretty_notifications = Notification.types.map { |n| " #{n[0]}: #{n[1]}," }.join("\n")
write_template("discourse/tests/fixtures/concerns/notification-types.js", task_name, <<~JS)
export const NOTIFICATION_TYPES = {
#{pretty_notifications}
};
JS
require "emoji/regex_generator"
write_template("pretty-text/addon/emoji/data.js", task_name, <<~JS)
export const emojis = new Set(#{Emoji.standard.map(&:name).flatten.inspect});
export const tonableEmojis = #{Emoji.tonable_emojis.flatten.inspect};
export const aliases = #{Emoji.aliases.inspect.gsub("=>", ":")};
export const translations = #{Emoji.translations.inspect.gsub("=>", ":")};
export const replacements = #{Emoji.unicode_replacements_json};
export const emojiReplacementRegex = "#{Emoji::RegexGenerator.generate}";
JS
write_template("pretty-text/addon/emoji/version.js", task_name, <<~JS)
export const IMAGE_VERSION = "#{Emoji::EMOJI_VERSION}";
JS
end