dbdoc_engine 0.1.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 +7 -0
- data/README.md +331 -0
- data/Rakefile +8 -0
- data/app/assets/builds/dbdoc_engine/application.css +5 -0
- data/app/assets/images/dbdoc_engine/arrowdown.svg +3 -0
- data/app/assets/images/dbdoc_engine/arrowhorizontal.svg +3 -0
- data/app/assets/images/dbdoc_engine/arrowleft.svg +3 -0
- data/app/assets/images/dbdoc_engine/changelog.svg +3 -0
- data/app/assets/images/dbdoc_engine/column_stats_dbdocs.svg +23 -0
- data/app/assets/images/dbdoc_engine/diagram.svg +3 -0
- data/app/assets/images/dbdoc_engine/double_arrow.svg +4 -0
- data/app/assets/images/dbdoc_engine/group_bu.svg +3 -0
- data/app/assets/images/dbdoc_engine/japan_circle.png +0 -0
- data/app/assets/images/dbdoc_engine/log_in_image.png +0 -0
- data/app/assets/images/dbdoc_engine/logo.svg +12 -0
- data/app/assets/images/dbdoc_engine/orange_changelog.svg +3 -0
- data/app/assets/images/dbdoc_engine/orange_fields.svg +23 -0
- data/app/assets/images/dbdoc_engine/orange_logo.svg +12 -0
- data/app/assets/images/dbdoc_engine/orange_table.svg +21 -0
- data/app/assets/images/dbdoc_engine/orange_updates.svg +43 -0
- data/app/assets/images/dbdoc_engine/orange_wiki.svg +3 -0
- data/app/assets/images/dbdoc_engine/search.svg +3 -0
- data/app/assets/images/dbdoc_engine/setting.svg +3 -0
- data/app/assets/images/dbdoc_engine/table_dbdocs.svg +21 -0
- data/app/assets/images/dbdoc_engine/uk_circle_transparent.png +0 -0
- data/app/assets/images/dbdoc_engine/update_stats_dbdocs.svg +43 -0
- data/app/assets/images/dbdoc_engine/wiki.svg +3 -0
- data/app/assets/stylesheets/dbdoc_engine/admin.css +176 -0
- data/app/assets/stylesheets/dbdoc_engine/admin_header.css +179 -0
- data/app/assets/stylesheets/dbdoc_engine/application.scss +1 -0
- data/app/assets/stylesheets/dbdoc_engine/changelog.css +173 -0
- data/app/assets/stylesheets/dbdoc_engine/dashboard.css +513 -0
- data/app/assets/stylesheets/dbdoc_engine/dbdoc_application.css +117 -0
- data/app/assets/stylesheets/dbdoc_engine/ecommerce.css +253 -0
- data/app/assets/stylesheets/dbdoc_engine/group_details.css +178 -0
- data/app/assets/stylesheets/dbdoc_engine/header.css +212 -0
- data/app/assets/stylesheets/dbdoc_engine/loading_spinner.css +127 -0
- data/app/assets/stylesheets/dbdoc_engine/login.css +213 -0
- data/app/assets/stylesheets/dbdoc_engine/schema_diagram.css +149 -0
- data/app/assets/stylesheets/dbdoc_engine/sidebar.css +296 -0
- data/app/assets/stylesheets/dbdoc_engine/table_details.css +417 -0
- data/app/controllers/dbdoc_engine/admin/base_controller.rb +23 -0
- data/app/controllers/dbdoc_engine/admin/dashboard_controller.rb +16 -0
- data/app/controllers/dbdoc_engine/admin/data_transfer_controller.rb +63 -0
- data/app/controllers/dbdoc_engine/admin/db_design_dynamic_tables_controller.rb +198 -0
- data/app/controllers/dbdoc_engine/admin/db_design_table_groups_controller.rb +107 -0
- data/app/controllers/dbdoc_engine/application_controller.rb +65 -0
- data/app/controllers/dbdoc_engine/concerns/internationalization.rb +57 -0
- data/app/controllers/dbdoc_engine/db_doc_sessions_controller.rb +33 -0
- data/app/controllers/dbdoc_engine/home_controller.rb +79 -0
- data/app/controllers/dbdoc_engine/schema_diagram_controller.rb +293 -0
- data/app/helper/dbdoc_engine/application_helper.rb +35 -0
- data/app/helpers/dbdoc_engine/application_helper.rb +4 -0
- data/app/helpers/dbdoc_engine/changelogs_helper.rb +27 -0
- data/app/helpers/dbdoc_engine/column_helper.rb +30 -0
- data/app/helpers/dbdoc_engine/db_design_dynamic_tables_helper.rb +15 -0
- data/app/helpers/dbdoc_engine/home_helper.rb +75 -0
- data/app/javascript/dbdoc_engine/application.js +12 -0
- data/app/javascript/dbdoc_engine/controllers/application.js +29 -0
- data/app/javascript/dbdoc_engine/controllers/auto_submit_controller.js +17 -0
- data/app/javascript/dbdoc_engine/controllers/chart_controller.js +58 -0
- data/app/javascript/dbdoc_engine/controllers/column-type_controller.js +149 -0
- data/app/javascript/dbdoc_engine/controllers/column_controller.js +362 -0
- data/app/javascript/dbdoc_engine/controllers/column_search_controller.js +42 -0
- data/app/javascript/dbdoc_engine/controllers/dbdoc_accordion_controller.js +42 -0
- data/app/javascript/dbdoc_engine/controllers/ecommerce_controller.js +73 -0
- data/app/javascript/dbdoc_engine/controllers/group_details_controller.js +88 -0
- data/app/javascript/dbdoc_engine/controllers/import_export_controller.js +200 -0
- data/app/javascript/dbdoc_engine/controllers/index.js +9 -0
- data/app/javascript/dbdoc_engine/controllers/language_controller.js +100 -0
- data/app/javascript/dbdoc_engine/controllers/loading_spinner_controller.js +48 -0
- data/app/javascript/dbdoc_engine/controllers/login_controller.js +75 -0
- data/app/javascript/dbdoc_engine/controllers/notification_controller.js +15 -0
- data/app/javascript/dbdoc_engine/controllers/schema_diagram_controller.js +1129 -0
- data/app/javascript/dbdoc_engine/controllers/select2_controller.js +67 -0
- data/app/javascript/dbdoc_engine/controllers/sidebar_controller.js +943 -0
- data/app/javascript/dbdoc_engine/controllers/table_details_controller.js +245 -0
- data/app/javascript/dbdoc_engine/controllers/table_group_validation_controller.js +148 -0
- data/app/javascript/dbdoc_engine/controllers/table_validation_controller.js +423 -0
- data/app/jobs/dbdoc_engine/application_job.rb +4 -0
- data/app/mailers/dbdoc_engine/application_mailer.rb +6 -0
- data/app/models/dbdoc_engine/application_record.rb +6 -0
- data/app/models/dbdoc_engine/concerns/soft_deletable.rb +30 -0
- data/app/models/dbdoc_engine/db_design_changelog.rb +44 -0
- data/app/models/dbdoc_engine/db_design_dynamic_column.rb +211 -0
- data/app/models/dbdoc_engine/db_design_dynamic_table.rb +124 -0
- data/app/models/dbdoc_engine/db_design_table_group.rb +88 -0
- data/app/models/dbdoc_engine/user.rb +21 -0
- data/app/queries/dbdoc_engine/admin_dashboard_queries.rb +71 -0
- data/app/queries/dbdoc_engine/db_design_changelog_queries.rb +68 -0
- data/app/queries/dbdoc_engine/db_design_dynamic_column_queries.rb +37 -0
- data/app/queries/dbdoc_engine/db_design_dynamic_table_commands.rb +106 -0
- data/app/queries/dbdoc_engine/db_design_dynamic_table_queries.rb +194 -0
- data/app/queries/dbdoc_engine/db_design_table_group_queries.rb +154 -0
- data/app/services/dbdoc_engine/db_design_dynamic_table_export_service.rb +38 -0
- data/app/services/dbdoc_engine/db_design_dynamic_table_handler_service.rb +49 -0
- data/app/services/dbdoc_engine/db_design_dynamic_tables_service.rb +21 -0
- data/app/services/dbdoc_engine/error_handler_service.rb +43 -0
- data/app/services/dbdoc_engine/schema_rb_import_service.rb +194 -0
- data/app/services/dbdoc_engine/schema_rb_parser_service.rb +339 -0
- data/app/services/dbdoc_engine/table_filter_service.rb +35 -0
- data/app/services/dbdoc_engine/table_groups_service.rb +199 -0
- data/app/services/dbdoc_engine/table_management_service.rb +192 -0
- data/app/views/dbdoc_engine/admin/dashboard/_action_badge.html.erb +11 -0
- data/app/views/dbdoc_engine/admin/dashboard/_changelog_rows.html.erb +22 -0
- data/app/views/dbdoc_engine/admin/dashboard/_changelog_table_headers.html.erb +8 -0
- data/app/views/dbdoc_engine/admin/dashboard/_filter_fields.html.erb +43 -0
- data/app/views/dbdoc_engine/admin/dashboard/index.html.erb +159 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_column_fields.html.erb +225 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_deleted_table_index.html.erb +110 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_foreign_key_fields.html.erb +51 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_form.html.erb +75 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_recent_activity.html.erb +39 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_columns.html.erb +127 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_index.html.erb +109 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_information.html.erb +99 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/deleted_tables.html.erb +95 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/edit.html.erb +23 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/export_all_to_excel.xlsx.axlsx +240 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/export_to_excel.xlsx.axlsx +135 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/index.html.erb +109 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/new.html.erb +25 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/show_table_info.html.erb +125 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/_deleted_table_groups_list.html.erb +75 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/_form.html.erb +88 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/_table_groups_list.html.erb +82 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/deleted_groups.html.erb +60 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/edit.html.erb +25 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/index.html.erb +85 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/new.html.erb +26 -0
- data/app/views/dbdoc_engine/db_doc_sessions/new.html.erb +59 -0
- data/app/views/dbdoc_engine/home/changelog_details.html.erb +80 -0
- data/app/views/dbdoc_engine/home/changelogs.html.erb +20 -0
- data/app/views/dbdoc_engine/home/group_details.html.erb +94 -0
- data/app/views/dbdoc_engine/home/index.html.erb +11 -0
- data/app/views/dbdoc_engine/home/partials/_action_badge.html.erb +11 -0
- data/app/views/dbdoc_engine/home/partials/_breadcrumb_navigation.html.erb +30 -0
- data/app/views/dbdoc_engine/home/partials/_changelog_rows.html.erb +35 -0
- data/app/views/dbdoc_engine/home/partials/_changelog_table_headers.html.erb +16 -0
- data/app/views/dbdoc_engine/home/partials/_column_headers.html.erb +23 -0
- data/app/views/dbdoc_engine/home/partials/_column_row.html.erb +157 -0
- data/app/views/dbdoc_engine/home/partials/_filter_form.html.erb +47 -0
- data/app/views/dbdoc_engine/home/partials/_group_section.html.erb +84 -0
- data/app/views/dbdoc_engine/home/partials/_pagination.html.erb +5 -0
- data/app/views/dbdoc_engine/home/partials/_stats_container.html.erb +46 -0
- data/app/views/dbdoc_engine/home/partials/_table_groups.html.erb +7 -0
- data/app/views/dbdoc_engine/home/partials/_table_information_section.html.erb +50 -0
- data/app/views/dbdoc_engine/home/partials/_table_section.html.erb +48 -0
- data/app/views/dbdoc_engine/home/table_details.html.erb +9 -0
- data/app/views/dbdoc_engine/schema_diagram/index.html.erb +102 -0
- data/app/views/dbdoc_engine/shared/_admin_header.html.erb +78 -0
- data/app/views/dbdoc_engine/shared/_header.html.erb +94 -0
- data/app/views/dbdoc_engine/shared/_js_translations.html.erb +3 -0
- data/app/views/dbdoc_engine/shared/_language_button.html.erb +14 -0
- data/app/views/dbdoc_engine/shared/_sidebar.html.erb +128 -0
- data/app/views/kaminari/dbdoc_engine/_first_page.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_gap.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_last_page.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_next_page.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_page.html.erb +9 -0
- data/app/views/kaminari/dbdoc_engine/_paginator.html.erb +17 -0
- data/app/views/kaminari/dbdoc_engine/_prev_page.html.erb +3 -0
- data/app/views/layouts/dbdoc_engine/application.html.erb +107 -0
- data/app/views/layouts/dbdoc_engine/header.html.erb +108 -0
- data/config/importmap.rb +11 -0
- data/config/locales/en.yml +307 -0
- data/config/locales/ja.yml +306 -0
- data/config/routes.rb +73 -0
- data/db/migrate/rails7/20250227060610_create_db_design_table_groups.rb +15 -0
- data/db/migrate/rails7/20250227094626_create_db_design_dynamic_tables.rb +19 -0
- data/db/migrate/rails7/20250228022732_create_db_design_dynamic_columns.rb +34 -0
- data/db/migrate/rails7/20250401051453_create_db_design_changelogs.rb +26 -0
- data/db/migrate/rails7/20250411040822_create_users.rb +14 -0
- data/db/migrate/rails7/20250421080851_add_missing_indexes_to_dbdoc_tables.rb +23 -0
- data/db/migrate/rails8/20250227060610_create_db_design_table_groups.rb +15 -0
- data/db/migrate/rails8/20250227094626_create_db_design_dynamic_tables.rb +19 -0
- data/db/migrate/rails8/20250228022732_create_db_design_dynamic_columns.rb +34 -0
- data/db/migrate/rails8/20250401051453_create_db_design_changelogs.rb +26 -0
- data/db/migrate/rails8/20250411040822_create_users.rb +14 -0
- data/db/migrate/rails8/20250421080851_add_missing_indexes_to_dbdoc_tables.rb +23 -0
- data/db/seeds.rb +28 -0
- data/lib/dbdoc_engine/engine.rb +57 -0
- data/lib/dbdoc_engine/version.rb +3 -0
- data/lib/dbdoc_engine.rb +9 -0
- data/lib/generators/dbdoc_engine/install/install_generator.rb +245 -0
- data/lib/generators/dbdoc_engine/uninstall/uninstall_generator.rb +196 -0
- data/lib/tasks/dbdoc_engine_tasks.rake +44 -0
- data/public/dbdoc_engine_assets/images/camel_chess_head.png +0 -0
- data/public/dbdoc_engine_assets/images/dblogo.svg +4 -0
- data/public/dbdoc_engine_assets/images/japan_circle.png +0 -0
- data/public/dbdoc_engine_assets/images/king_chess_head.png +0 -0
- data/public/dbdoc_engine_assets/images/login-bg.svg +44 -0
- data/public/dbdoc_engine_assets/images/logo.png +0 -0
- data/public/dbdoc_engine_assets/images/logo.svg +12 -0
- data/public/dbdoc_engine_assets/images/queen_chess_head.png +0 -0
- data/public/dbdoc_engine_assets/images/soldier_chess_headd.png +0 -0
- data/public/dbdoc_engine_assets/images/uk_circle_transparent.png +0 -0
- metadata +415 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require "rails/generators/base"
|
|
3
|
+
require "rake"
|
|
4
|
+
|
|
5
|
+
module DbdocEngine
|
|
6
|
+
module Generators
|
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
|
8
|
+
desc "Install DbdocEngine: copies migrations, seeds default users, configures routes and JS"
|
|
9
|
+
|
|
10
|
+
source_root File.expand_path("templates", __dir__)
|
|
11
|
+
|
|
12
|
+
def welcome
|
|
13
|
+
say ""
|
|
14
|
+
say "=" * 60, :green
|
|
15
|
+
say " DbdocEngine Installer", :green
|
|
16
|
+
say "=" * 60, :green
|
|
17
|
+
say ""
|
|
18
|
+
say " This will set up DbdocEngine in your Rails application.", :cyan
|
|
19
|
+
say " Rails version detected: #{Rails.version}", :cyan
|
|
20
|
+
say ""
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def check_prerequisites
|
|
24
|
+
say_step "Checking prerequisites..."
|
|
25
|
+
|
|
26
|
+
unless defined?(ActiveRecord::Base)
|
|
27
|
+
say "ERROR: ActiveRecord is required. Please ensure your app uses ActiveRecord.", :red
|
|
28
|
+
raise SystemExit
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
db_config = ActiveRecord::Base.connection_db_config
|
|
32
|
+
say_done "Database: #{db_config.adapter} (#{db_config.database})"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def copy_and_run_migrations
|
|
36
|
+
rails_version = Rails.version.to_f
|
|
37
|
+
|
|
38
|
+
say_step "Copying migrations (Rails #{rails_version >= 8.0 ? '8.x' : '7.x'})..."
|
|
39
|
+
copy_migrations(rails_version)
|
|
40
|
+
say_done "Migrations copied"
|
|
41
|
+
|
|
42
|
+
Rake::Task.clear
|
|
43
|
+
Rails.application.load_tasks
|
|
44
|
+
|
|
45
|
+
invoke_task("dbdoc_engine:install:migrations", "Installing engine migrations")
|
|
46
|
+
invoke_task("db:migrate", "Running migrations")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def seed_default_users
|
|
50
|
+
say_step "Seeding default users..."
|
|
51
|
+
|
|
52
|
+
Rake::Task.clear
|
|
53
|
+
Rails.application.load_tasks
|
|
54
|
+
|
|
55
|
+
invoke_task("dbdoc_engine:install:seeds", "Copying seed file")
|
|
56
|
+
invoke_task("dbdoc_engine:db:seed", "Creating default users")
|
|
57
|
+
|
|
58
|
+
say_done "Default users created (user / admin / superadmin)"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def setup_javascript
|
|
62
|
+
rails_version = Rails.version.to_f
|
|
63
|
+
|
|
64
|
+
if rails_version < 8.0
|
|
65
|
+
install_js_stack
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
update_importmap
|
|
69
|
+
update_application_js
|
|
70
|
+
|
|
71
|
+
if rails_version < 8.0
|
|
72
|
+
update_manifest
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def setup_routes
|
|
77
|
+
update_routes
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def complete
|
|
81
|
+
say ""
|
|
82
|
+
say "=" * 60, :green
|
|
83
|
+
say " DbdocEngine installed successfully!", :green
|
|
84
|
+
say "=" * 60, :green
|
|
85
|
+
say ""
|
|
86
|
+
say " Access your documentation at: http://localhost:3000/dbdoc", :cyan
|
|
87
|
+
say ""
|
|
88
|
+
say " Default login credentials:", :cyan
|
|
89
|
+
say " user / password123 (read-only)", :cyan
|
|
90
|
+
say " admin / password123 (can edit)", :cyan
|
|
91
|
+
say " superadmin/ password123 (full control)", :cyan
|
|
92
|
+
say ""
|
|
93
|
+
say " To uninstall later:", :yellow
|
|
94
|
+
say " bin/rails generate dbdoc_engine:uninstall", :yellow
|
|
95
|
+
say ""
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def copy_migrations(rails_version)
|
|
101
|
+
source_dir = rails_version >= 8.0 ? "rails8" : "rails7"
|
|
102
|
+
Dir[File.join(self.class.source_root, "db/migrate/#{source_dir}/*.rb")].each do |file|
|
|
103
|
+
dest = "db/migrate/#{File.basename(file)}"
|
|
104
|
+
if File.exist?(File.join(destination_root, dest))
|
|
105
|
+
say_status("exists", dest, :blue)
|
|
106
|
+
else
|
|
107
|
+
copy_file file, dest
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def install_js_stack
|
|
113
|
+
importmap_path = File.join(destination_root, "config/importmap.rb")
|
|
114
|
+
js_path = File.join(destination_root, "app/javascript/application.js")
|
|
115
|
+
unless File.exist?(importmap_path) && File.exist?(js_path)
|
|
116
|
+
say_step "Installing Importmap, Turbo, and Stimulus..."
|
|
117
|
+
system("rails importmap:install")
|
|
118
|
+
system("rails turbo:install stimulus:install")
|
|
119
|
+
say_done "JS stack installed"
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def invoke_task(task, message)
|
|
124
|
+
say_step "#{message}..."
|
|
125
|
+
Rake::Task[task].reenable
|
|
126
|
+
Rake::Task[task].invoke
|
|
127
|
+
say_done message
|
|
128
|
+
rescue RuntimeError => e
|
|
129
|
+
say " Warning: #{e.message}", :yellow
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def update_routes
|
|
133
|
+
routes_path = File.join(destination_root, "config/routes.rb")
|
|
134
|
+
mount_line = " mount DbdocEngine::Engine => \"/dbdoc\"\n"
|
|
135
|
+
|
|
136
|
+
content = File.read(routes_path)
|
|
137
|
+
if content.include?("mount DbdocEngine::Engine")
|
|
138
|
+
say_done "Route already configured"
|
|
139
|
+
return
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
say_step "Adding engine route to routes.rb..."
|
|
143
|
+
new_content = content.sub(
|
|
144
|
+
/Rails\.application\.routes\.draw do\n/,
|
|
145
|
+
"Rails.application.routes.draw do\n#{mount_line}"
|
|
146
|
+
)
|
|
147
|
+
File.write(routes_path, new_content)
|
|
148
|
+
say_done "Route added: mount DbdocEngine::Engine => \"/dbdoc\""
|
|
149
|
+
rescue StandardError => e
|
|
150
|
+
say " Warning: Could not update routes.rb: #{e.message}", :yellow
|
|
151
|
+
say " Please add manually: mount DbdocEngine::Engine => \"/dbdoc\"", :yellow
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def update_importmap
|
|
155
|
+
importmap_path = File.join(destination_root, "config/importmap.rb")
|
|
156
|
+
pin_code = <<~RUBY
|
|
157
|
+
|
|
158
|
+
if defined?(DbdocEngine)
|
|
159
|
+
pin_all_from DbdocEngine::Engine.root.join("app/javascript/dbdoc_engine"),
|
|
160
|
+
under: "dbdoc_engine",
|
|
161
|
+
to: "dbdoc_engine"
|
|
162
|
+
end
|
|
163
|
+
RUBY
|
|
164
|
+
|
|
165
|
+
content = File.exist?(importmap_path) ? File.read(importmap_path) : ""
|
|
166
|
+
if content.include?("pin_all_from DbdocEngine::Engine.root.join")
|
|
167
|
+
say_done "Importmap pins already configured"
|
|
168
|
+
return
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
say_step "Adding pins to importmap.rb..."
|
|
172
|
+
File.open(importmap_path, "a") { |f| f.puts pin_code }
|
|
173
|
+
say_done "Importmap pins added"
|
|
174
|
+
rescue StandardError => e
|
|
175
|
+
say " Warning: Could not update importmap.rb: #{e.message}", :yellow
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def update_application_js
|
|
179
|
+
js_path = File.join(destination_root, "app/javascript/application.js")
|
|
180
|
+
import_line = 'import "dbdoc_engine/application";'
|
|
181
|
+
|
|
182
|
+
content = File.exist?(js_path) ? File.read(js_path) : ""
|
|
183
|
+
if content.include?(import_line)
|
|
184
|
+
say_done "application.js already configured"
|
|
185
|
+
return
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
say_step "Adding import to application.js..."
|
|
189
|
+
File.write(js_path, "#{import_line}\n#{content}")
|
|
190
|
+
say_done "JS import added"
|
|
191
|
+
rescue StandardError => e
|
|
192
|
+
say " Warning: Could not update application.js: #{e.message}", :yellow
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def update_manifest
|
|
196
|
+
manifest_path = File.join(destination_root, "app/assets/config/manifest.js")
|
|
197
|
+
manifest_code = <<~JS.chomp
|
|
198
|
+
//= link_tree ../images
|
|
199
|
+
//= link_directory ../stylesheets .css
|
|
200
|
+
//= link dbdoc_engine/log_in_image.png
|
|
201
|
+
//= link dbdoc_engine/dbdoc_application.css
|
|
202
|
+
//= link dbdoc_engine/header.css
|
|
203
|
+
//= link dbdoc_engine/sidebar.css
|
|
204
|
+
//= link dbdoc_engine/ecommerce.css
|
|
205
|
+
//= link dbdoc_engine/group_details.css
|
|
206
|
+
//= link dbdoc_engine/table_details.css
|
|
207
|
+
//= link dbdoc_engine/changelog.css
|
|
208
|
+
//= link dbdoc_engine/loading_spinner.css
|
|
209
|
+
//= link dbdoc_engine/dashboard.css
|
|
210
|
+
//= link dbdoc_engine/schema_diagram.css
|
|
211
|
+
//= link dbdoc_engine/admin_header.css
|
|
212
|
+
//= link dbdoc_engine/login.css
|
|
213
|
+
//= link dbdoc_engine/admin.css
|
|
214
|
+
//= link_tree ../../javascript
|
|
215
|
+
//= link_tree ../../../vendor/javascript
|
|
216
|
+
JS
|
|
217
|
+
|
|
218
|
+
if File.exist?(manifest_path)
|
|
219
|
+
content = File.read(manifest_path)
|
|
220
|
+
if content.include?("dbdoc_engine/log_in_image.png")
|
|
221
|
+
say_done "manifest.js already configured"
|
|
222
|
+
return
|
|
223
|
+
end
|
|
224
|
+
say_step "Adding assets to manifest.js..."
|
|
225
|
+
File.open(manifest_path, "a") { |f| f.puts manifest_code }
|
|
226
|
+
else
|
|
227
|
+
say_step "Creating manifest.js..."
|
|
228
|
+
FileUtils.mkdir_p(File.dirname(manifest_path))
|
|
229
|
+
File.write(manifest_path, manifest_code)
|
|
230
|
+
end
|
|
231
|
+
say_done "manifest.js updated"
|
|
232
|
+
rescue StandardError => e
|
|
233
|
+
say " Warning: Could not update manifest.js: #{e.message}", :yellow
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def say_step(message)
|
|
237
|
+
say " ▶ #{message}", :yellow
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def say_done(message)
|
|
241
|
+
say " ✔ #{message}", :green
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require "rails/generators/base"
|
|
3
|
+
|
|
4
|
+
module DbdocEngine
|
|
5
|
+
module Generators
|
|
6
|
+
class UninstallGenerator < Rails::Generators::Base
|
|
7
|
+
desc "Uninstall DbdocEngine: removes all engine tables, routes, importmap pins, and JS imports"
|
|
8
|
+
|
|
9
|
+
DBDOC_TABLES = %w[
|
|
10
|
+
db_design_dynamic_columns
|
|
11
|
+
db_design_dynamic_tables
|
|
12
|
+
db_design_table_groups
|
|
13
|
+
db_design_changelogs
|
|
14
|
+
dbdoc_engine_users
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
def confirm_uninstall
|
|
18
|
+
say ""
|
|
19
|
+
say "=" * 60, :red
|
|
20
|
+
say " DbdocEngine Uninstall", :red
|
|
21
|
+
say "=" * 60, :red
|
|
22
|
+
say ""
|
|
23
|
+
say "This will permanently remove the following from your application:", :yellow
|
|
24
|
+
say ""
|
|
25
|
+
say " DATABASE TABLES:", :yellow
|
|
26
|
+
DBDOC_TABLES.each { |t| say " - #{t}", :red }
|
|
27
|
+
say ""
|
|
28
|
+
say " FILES & CONFIG:", :yellow
|
|
29
|
+
say " - DbdocEngine route from config/routes.rb", :red
|
|
30
|
+
say " - DbdocEngine pins from config/importmap.rb", :red
|
|
31
|
+
say " - DbdocEngine import from app/javascript/application.js", :red
|
|
32
|
+
say " - Seed file db/dbdoc_engine_seeds.rb", :red
|
|
33
|
+
say ""
|
|
34
|
+
say "=" * 60, :red
|
|
35
|
+
say ""
|
|
36
|
+
|
|
37
|
+
unless yes?("Are you sure you want to uninstall DbdocEngine? (y/N)", :red)
|
|
38
|
+
say "Uninstall cancelled.", :green
|
|
39
|
+
raise SystemExit
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
say ""
|
|
43
|
+
if yes?("Do you want to DROP all DbdocEngine tables? This cannot be undone! (y/N)", :red)
|
|
44
|
+
@drop_tables = true
|
|
45
|
+
else
|
|
46
|
+
say "Tables will be preserved. You can drop them manually later.", :yellow
|
|
47
|
+
@drop_tables = false
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def drop_tables
|
|
52
|
+
return unless @drop_tables
|
|
53
|
+
|
|
54
|
+
say ""
|
|
55
|
+
say_status("uninstall", "Dropping DbdocEngine tables...", :yellow)
|
|
56
|
+
|
|
57
|
+
DBDOC_TABLES.each do |table_name|
|
|
58
|
+
if table_exists?(table_name)
|
|
59
|
+
ActiveRecord::Base.connection.drop_table(table_name, force: :cascade)
|
|
60
|
+
say_status("dropped", table_name, :red)
|
|
61
|
+
else
|
|
62
|
+
say_status("skipped", "#{table_name} (does not exist)", :cyan)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
remove_migration_entries
|
|
67
|
+
say_status("done", "All DbdocEngine tables dropped", :green)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def remove_route
|
|
71
|
+
routes_path = File.join(destination_root, "config/routes.rb")
|
|
72
|
+
return unless File.exist?(routes_path)
|
|
73
|
+
|
|
74
|
+
content = File.read(routes_path)
|
|
75
|
+
if content.include?("DbdocEngine::Engine")
|
|
76
|
+
say_status("uninstall", "Removing DbdocEngine route...", :yellow)
|
|
77
|
+
new_content = content.gsub(/^\s*mount\s+DbdocEngine::Engine.*\n/, "")
|
|
78
|
+
File.write(routes_path, new_content)
|
|
79
|
+
say_status("removed", "DbdocEngine route from routes.rb", :green)
|
|
80
|
+
else
|
|
81
|
+
say_status("skipped", "No DbdocEngine route found in routes.rb", :cyan)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def remove_importmap_pins
|
|
86
|
+
importmap_path = File.join(destination_root, "config/importmap.rb")
|
|
87
|
+
return unless File.exist?(importmap_path)
|
|
88
|
+
|
|
89
|
+
content = File.read(importmap_path)
|
|
90
|
+
if content.include?("DbdocEngine")
|
|
91
|
+
say_status("uninstall", "Removing DbdocEngine importmap pins...", :yellow)
|
|
92
|
+
new_content = content.gsub(/\n*\s*if defined\?\(DbdocEngine\).*?end\n?/m, "\n")
|
|
93
|
+
File.write(importmap_path, new_content)
|
|
94
|
+
say_status("removed", "DbdocEngine pins from importmap.rb", :green)
|
|
95
|
+
else
|
|
96
|
+
say_status("skipped", "No DbdocEngine pins found in importmap.rb", :cyan)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def remove_js_import
|
|
101
|
+
js_path = File.join(destination_root, "app/javascript/application.js")
|
|
102
|
+
return unless File.exist?(js_path)
|
|
103
|
+
|
|
104
|
+
content = File.read(js_path)
|
|
105
|
+
if content.include?("dbdoc_engine")
|
|
106
|
+
say_status("uninstall", "Removing DbdocEngine JS import...", :yellow)
|
|
107
|
+
new_content = content.gsub(/^.*dbdoc_engine.*\n?/, "")
|
|
108
|
+
File.write(js_path, new_content)
|
|
109
|
+
say_status("removed", "DbdocEngine import from application.js", :green)
|
|
110
|
+
else
|
|
111
|
+
say_status("skipped", "No DbdocEngine import found in application.js", :cyan)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def remove_seed_file
|
|
116
|
+
seed_file = File.join(destination_root, "db/dbdoc_engine_seeds.rb")
|
|
117
|
+
if File.exist?(seed_file)
|
|
118
|
+
say_status("uninstall", "Removing seed file...", :yellow)
|
|
119
|
+
File.delete(seed_file)
|
|
120
|
+
say_status("removed", "db/dbdoc_engine_seeds.rb", :green)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def remove_manifest_entries
|
|
125
|
+
manifest_path = File.join(destination_root, "app/assets/config/manifest.js")
|
|
126
|
+
return unless File.exist?(manifest_path)
|
|
127
|
+
|
|
128
|
+
content = File.read(manifest_path)
|
|
129
|
+
if content.include?("dbdoc_engine")
|
|
130
|
+
say_status("uninstall", "Removing DbdocEngine manifest entries...", :yellow)
|
|
131
|
+
new_content = content.gsub(/^.*dbdoc_engine.*\n?/, "")
|
|
132
|
+
File.write(manifest_path, new_content)
|
|
133
|
+
say_status("removed", "DbdocEngine entries from manifest.js", :green)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def final_instructions
|
|
138
|
+
say ""
|
|
139
|
+
say "=" * 60, :green
|
|
140
|
+
say " DbdocEngine has been uninstalled", :green
|
|
141
|
+
say "=" * 60, :green
|
|
142
|
+
say ""
|
|
143
|
+
say "Next steps:", :yellow
|
|
144
|
+
say " 1. Remove 'gem \"dbdoc_engine\"' from your Gemfile", :yellow
|
|
145
|
+
say " 2. Run 'bundle install'", :yellow
|
|
146
|
+
unless @drop_tables
|
|
147
|
+
say " 3. Manually drop DbdocEngine tables if needed:", :yellow
|
|
148
|
+
DBDOC_TABLES.each { |t| say " DROP TABLE IF EXISTS #{t} CASCADE;", :cyan }
|
|
149
|
+
end
|
|
150
|
+
say ""
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
|
|
155
|
+
def table_exists?(table_name)
|
|
156
|
+
ActiveRecord::Base.connection.table_exists?(table_name)
|
|
157
|
+
rescue StandardError
|
|
158
|
+
false
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def remove_migration_entries
|
|
162
|
+
if ActiveRecord::Base.connection.table_exists?(:schema_migrations)
|
|
163
|
+
migration_versions = Dir[File.join(destination_root, "db/migrate/*dbdoc*")].map do |f|
|
|
164
|
+
File.basename(f).split("_").first
|
|
165
|
+
end
|
|
166
|
+
migration_versions.concat(
|
|
167
|
+
Dir[File.join(destination_root, "db/migrate/*db_design*")].map do |f|
|
|
168
|
+
File.basename(f).split("_").first
|
|
169
|
+
end
|
|
170
|
+
)
|
|
171
|
+
migration_versions.concat(
|
|
172
|
+
Dir[File.join(destination_root, "db/migrate/*create_users*")].map do |f|
|
|
173
|
+
File.basename(f).split("_").first
|
|
174
|
+
end
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
migration_versions.uniq.each do |version|
|
|
178
|
+
ActiveRecord::Base.connection.execute(
|
|
179
|
+
"DELETE FROM schema_migrations WHERE version = '#{version}'"
|
|
180
|
+
)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
migration_files = Dir[File.join(destination_root, "db/migrate/*db_design*")] +
|
|
184
|
+
Dir[File.join(destination_root, "db/migrate/*dbdoc*")] +
|
|
185
|
+
Dir[File.join(destination_root, "db/migrate/*create_users*")]
|
|
186
|
+
migration_files.uniq.each do |f|
|
|
187
|
+
File.delete(f) if File.exist?(f)
|
|
188
|
+
say_status("removed", "Migration: #{File.basename(f)}", :red)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
rescue StandardError => e
|
|
192
|
+
say "Warning: Could not clean migration entries: #{e.message}", :yellow
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# lib/tasks/dbdoc_engine_tasks.rake
|
|
2
|
+
|
|
3
|
+
namespace :dbdoc_engine do
|
|
4
|
+
namespace :install do
|
|
5
|
+
desc 'Copy seed file from dbdoc_engine to host application'
|
|
6
|
+
task :seeds do
|
|
7
|
+
# Path to the gem's seed file
|
|
8
|
+
source_file = File.join(DbdocEngine::Engine.root, 'db', 'seeds.rb')
|
|
9
|
+
|
|
10
|
+
# Path to the host application's seeds directory
|
|
11
|
+
seeds_dir = File.join(Rails.root, 'db')
|
|
12
|
+
|
|
13
|
+
# Create destination filename (avoid overwriting existing seeds.rb)
|
|
14
|
+
destination_file = File.join(seeds_dir, 'dbdoc_engine_seeds.rb')
|
|
15
|
+
|
|
16
|
+
# Ensure the directory exists
|
|
17
|
+
FileUtils.mkdir_p(seeds_dir)
|
|
18
|
+
|
|
19
|
+
# Copy the file
|
|
20
|
+
if File.exist?(source_file)
|
|
21
|
+
FileUtils.cp(source_file, destination_file)
|
|
22
|
+
puts "Copied dbdoc_engine seeds to #{destination_file}"
|
|
23
|
+
else
|
|
24
|
+
puts "No seed file found at #{source_file}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
namespace :db do
|
|
30
|
+
desc 'Load the seed data from dbdoc_engine'
|
|
31
|
+
task :seed => :environment do
|
|
32
|
+
# Path to the seed file in the host application
|
|
33
|
+
seed_file = File.join(Rails.root, 'db', 'dbdoc_engine_seeds.rb')
|
|
34
|
+
|
|
35
|
+
# If the file exists, load it
|
|
36
|
+
if File.exist?(seed_file)
|
|
37
|
+
load(seed_file)
|
|
38
|
+
puts "Loaded dbdoc_engine seed data"
|
|
39
|
+
else
|
|
40
|
+
puts "No seed file found at #{seed_file}. Run 'rake dbdoc_engine:install:seeds' first."
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
Binary file
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="495.03 495.03 1009.94 1009.94" width="107.77" height="107.77" xml:space="preserve" style="fill-rule: evenodd; clip-rule: evenodd; stroke-linejoin: round; stroke-miterlimit: 2; position: absolute;">
|
|
2
|
+
<path transform="matrix(1.68137,0,0,1.68137,-146.171,265.639)" d="M381.356,343.146L381.356,136.431L527.189,136.431L527.189,343.14L527.189,488.979L381.356,343.146Z" style="fill: #5366A0; fill-opacity: 1;"></path>
|
|
3
|
+
<path transform="matrix(1.68137,0,0,1.68137,-146.171,265.639)" d="M681.688,737.095L381.356,737.095L381.356,737.089L527.189,591.256L527.189,591.261L681.688,591.261C767.015,591.261 836.186,522.09 836.186,436.763C836.186,351.436 767.015,282.264 681.688,282.264L591.014,282.264L591.014,136.431L681.688,136.431C847.557,136.431 982.02,270.894 982.02,436.763C982.02,493.264 966.417,546.122 939.286,591.261C913.9,633.496 878.421,668.975 836.186,694.361C813.824,707.802 789.567,718.414 763.911,725.701C737.78,733.122 710.198,737.095 681.688,737.095Z" style="fill: rgb(255, 255, 255); fill-opacity: 1;"></path>
|
|
4
|
+
</svg>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<svg width="1920" height="1080" viewBox="0 0 1920 1080" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<!-- Main gradient -->
|
|
4
|
+
<linearGradient id="main-gradient" x1="0" y1="0" x2="1920" y2="0" gradientUnits="userSpaceOnUse">
|
|
5
|
+
<stop offset="0%" stop-color="#829ED4"/>
|
|
6
|
+
<stop offset="100%" stop-color="#364380"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
<!-- White glow top right -->
|
|
9
|
+
<radialGradient id="white-glow" cx="80%" cy="10%" r="1">
|
|
10
|
+
<stop offset="0%" stop-color="#fff" stop-opacity="0.33"/>
|
|
11
|
+
<stop offset="90%" stop-color="#fff" stop-opacity="0"/>
|
|
12
|
+
</radialGradient>
|
|
13
|
+
<!-- Soft blue accent bottom left -->
|
|
14
|
+
<radialGradient id="accent" cx="15%" cy="90%" r="1">
|
|
15
|
+
<stop offset="0%" stop-color="#829ED4" stop-opacity="0.18"/>
|
|
16
|
+
<stop offset="100%" stop-color="#364380" stop-opacity="0"/>
|
|
17
|
+
</radialGradient>
|
|
18
|
+
<!-- Pink highlight wave -->
|
|
19
|
+
<linearGradient id="wave-pink" x1="0" y1="920" x2="1920" y2="1080" gradientUnits="userSpaceOnUse">
|
|
20
|
+
<stop offset="0%" stop-color="#f3d1ff" stop-opacity="0.13"/>
|
|
21
|
+
<stop offset="100%" stop-color="#829ED4" stop-opacity="0"/>
|
|
22
|
+
</linearGradient>
|
|
23
|
+
<!-- Blue overlay wave -->
|
|
24
|
+
<linearGradient id="wave-blue" x1="0" y1="1060" x2="1920" y2="980" gradientUnits="userSpaceOnUse">
|
|
25
|
+
<stop offset="0%" stop-color="#364380" stop-opacity="0.13"/>
|
|
26
|
+
<stop offset="100%" stop-color="#829ED4" stop-opacity="0"/>
|
|
27
|
+
</linearGradient>
|
|
28
|
+
</defs>
|
|
29
|
+
<!-- Main gradient background -->
|
|
30
|
+
<rect width="1920" height="1080" fill="url(#main-gradient)"/>
|
|
31
|
+
<!-- Soft white glow in the top right -->
|
|
32
|
+
<ellipse cx="1700" cy="120" rx="440" ry="280" fill="url(#white-glow)"/>
|
|
33
|
+
<!-- Soft blue accent in the bottom left -->
|
|
34
|
+
<ellipse cx="180" cy="1040" rx="400" ry="180" fill="url(#accent)"/>
|
|
35
|
+
<!-- Abstract pinkish wave overlay bottom -->
|
|
36
|
+
<path d="M0 950 Q 400 1100 1000 1000 T 1920 1080 V1080 H0Z" fill="url(#wave-pink)"/>
|
|
37
|
+
<!-- Abstract blue wave overlay bottom -->
|
|
38
|
+
<path d="M0 1040 Q 800 1160 1700 1040 T 1920 1080 V1080 H0Z" fill="url(#wave-blue)"/>
|
|
39
|
+
<!-- Subtle circles for extra depth -->
|
|
40
|
+
<circle cx="1600" cy="900" r="120" fill="#fff" opacity="0.03"/>
|
|
41
|
+
<circle cx="420" cy="160" r="80" fill="#fff" opacity="0.04"/>
|
|
42
|
+
<circle cx="1450" cy="300" r="60" fill="#fff" opacity="0.06"/>
|
|
43
|
+
<circle cx="350" cy="800" r="50" fill="#fff" opacity="0.04"/>
|
|
44
|
+
</svg>
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg width="35" height="35" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Background Circle -->
|
|
3
|
+
<circle cx="25" cy="25" r="25" fill="white" />
|
|
4
|
+
|
|
5
|
+
<!-- Table Icon -->
|
|
6
|
+
<rect x="12" y="12" width="20" height="5" rx="3" fill="#5366A0"/>
|
|
7
|
+
<rect x="12" y="20" width="20" height="5" rx="3" fill="#5366A0"/>
|
|
8
|
+
<rect x="12" y="28" width="20" height="5" rx="3" fill="#5366A0"/>
|
|
9
|
+
|
|
10
|
+
<!-- Shield Icon (Attached to the Bottom Right) -->
|
|
11
|
+
<path d="M30 28 L40 30 L40 37 Q35 42 30 37 Z" fill="#5366A0" stroke="#5366A0" stroke-width="2"/>
|
|
12
|
+
</svg>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|