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.
Files changed (198) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +331 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/builds/dbdoc_engine/application.css +5 -0
  5. data/app/assets/images/dbdoc_engine/arrowdown.svg +3 -0
  6. data/app/assets/images/dbdoc_engine/arrowhorizontal.svg +3 -0
  7. data/app/assets/images/dbdoc_engine/arrowleft.svg +3 -0
  8. data/app/assets/images/dbdoc_engine/changelog.svg +3 -0
  9. data/app/assets/images/dbdoc_engine/column_stats_dbdocs.svg +23 -0
  10. data/app/assets/images/dbdoc_engine/diagram.svg +3 -0
  11. data/app/assets/images/dbdoc_engine/double_arrow.svg +4 -0
  12. data/app/assets/images/dbdoc_engine/group_bu.svg +3 -0
  13. data/app/assets/images/dbdoc_engine/japan_circle.png +0 -0
  14. data/app/assets/images/dbdoc_engine/log_in_image.png +0 -0
  15. data/app/assets/images/dbdoc_engine/logo.svg +12 -0
  16. data/app/assets/images/dbdoc_engine/orange_changelog.svg +3 -0
  17. data/app/assets/images/dbdoc_engine/orange_fields.svg +23 -0
  18. data/app/assets/images/dbdoc_engine/orange_logo.svg +12 -0
  19. data/app/assets/images/dbdoc_engine/orange_table.svg +21 -0
  20. data/app/assets/images/dbdoc_engine/orange_updates.svg +43 -0
  21. data/app/assets/images/dbdoc_engine/orange_wiki.svg +3 -0
  22. data/app/assets/images/dbdoc_engine/search.svg +3 -0
  23. data/app/assets/images/dbdoc_engine/setting.svg +3 -0
  24. data/app/assets/images/dbdoc_engine/table_dbdocs.svg +21 -0
  25. data/app/assets/images/dbdoc_engine/uk_circle_transparent.png +0 -0
  26. data/app/assets/images/dbdoc_engine/update_stats_dbdocs.svg +43 -0
  27. data/app/assets/images/dbdoc_engine/wiki.svg +3 -0
  28. data/app/assets/stylesheets/dbdoc_engine/admin.css +176 -0
  29. data/app/assets/stylesheets/dbdoc_engine/admin_header.css +179 -0
  30. data/app/assets/stylesheets/dbdoc_engine/application.scss +1 -0
  31. data/app/assets/stylesheets/dbdoc_engine/changelog.css +173 -0
  32. data/app/assets/stylesheets/dbdoc_engine/dashboard.css +513 -0
  33. data/app/assets/stylesheets/dbdoc_engine/dbdoc_application.css +117 -0
  34. data/app/assets/stylesheets/dbdoc_engine/ecommerce.css +253 -0
  35. data/app/assets/stylesheets/dbdoc_engine/group_details.css +178 -0
  36. data/app/assets/stylesheets/dbdoc_engine/header.css +212 -0
  37. data/app/assets/stylesheets/dbdoc_engine/loading_spinner.css +127 -0
  38. data/app/assets/stylesheets/dbdoc_engine/login.css +213 -0
  39. data/app/assets/stylesheets/dbdoc_engine/schema_diagram.css +149 -0
  40. data/app/assets/stylesheets/dbdoc_engine/sidebar.css +296 -0
  41. data/app/assets/stylesheets/dbdoc_engine/table_details.css +417 -0
  42. data/app/controllers/dbdoc_engine/admin/base_controller.rb +23 -0
  43. data/app/controllers/dbdoc_engine/admin/dashboard_controller.rb +16 -0
  44. data/app/controllers/dbdoc_engine/admin/data_transfer_controller.rb +63 -0
  45. data/app/controllers/dbdoc_engine/admin/db_design_dynamic_tables_controller.rb +198 -0
  46. data/app/controllers/dbdoc_engine/admin/db_design_table_groups_controller.rb +107 -0
  47. data/app/controllers/dbdoc_engine/application_controller.rb +65 -0
  48. data/app/controllers/dbdoc_engine/concerns/internationalization.rb +57 -0
  49. data/app/controllers/dbdoc_engine/db_doc_sessions_controller.rb +33 -0
  50. data/app/controllers/dbdoc_engine/home_controller.rb +79 -0
  51. data/app/controllers/dbdoc_engine/schema_diagram_controller.rb +293 -0
  52. data/app/helper/dbdoc_engine/application_helper.rb +35 -0
  53. data/app/helpers/dbdoc_engine/application_helper.rb +4 -0
  54. data/app/helpers/dbdoc_engine/changelogs_helper.rb +27 -0
  55. data/app/helpers/dbdoc_engine/column_helper.rb +30 -0
  56. data/app/helpers/dbdoc_engine/db_design_dynamic_tables_helper.rb +15 -0
  57. data/app/helpers/dbdoc_engine/home_helper.rb +75 -0
  58. data/app/javascript/dbdoc_engine/application.js +12 -0
  59. data/app/javascript/dbdoc_engine/controllers/application.js +29 -0
  60. data/app/javascript/dbdoc_engine/controllers/auto_submit_controller.js +17 -0
  61. data/app/javascript/dbdoc_engine/controllers/chart_controller.js +58 -0
  62. data/app/javascript/dbdoc_engine/controllers/column-type_controller.js +149 -0
  63. data/app/javascript/dbdoc_engine/controllers/column_controller.js +362 -0
  64. data/app/javascript/dbdoc_engine/controllers/column_search_controller.js +42 -0
  65. data/app/javascript/dbdoc_engine/controllers/dbdoc_accordion_controller.js +42 -0
  66. data/app/javascript/dbdoc_engine/controllers/ecommerce_controller.js +73 -0
  67. data/app/javascript/dbdoc_engine/controllers/group_details_controller.js +88 -0
  68. data/app/javascript/dbdoc_engine/controllers/import_export_controller.js +200 -0
  69. data/app/javascript/dbdoc_engine/controllers/index.js +9 -0
  70. data/app/javascript/dbdoc_engine/controllers/language_controller.js +100 -0
  71. data/app/javascript/dbdoc_engine/controllers/loading_spinner_controller.js +48 -0
  72. data/app/javascript/dbdoc_engine/controllers/login_controller.js +75 -0
  73. data/app/javascript/dbdoc_engine/controllers/notification_controller.js +15 -0
  74. data/app/javascript/dbdoc_engine/controllers/schema_diagram_controller.js +1129 -0
  75. data/app/javascript/dbdoc_engine/controllers/select2_controller.js +67 -0
  76. data/app/javascript/dbdoc_engine/controllers/sidebar_controller.js +943 -0
  77. data/app/javascript/dbdoc_engine/controllers/table_details_controller.js +245 -0
  78. data/app/javascript/dbdoc_engine/controllers/table_group_validation_controller.js +148 -0
  79. data/app/javascript/dbdoc_engine/controllers/table_validation_controller.js +423 -0
  80. data/app/jobs/dbdoc_engine/application_job.rb +4 -0
  81. data/app/mailers/dbdoc_engine/application_mailer.rb +6 -0
  82. data/app/models/dbdoc_engine/application_record.rb +6 -0
  83. data/app/models/dbdoc_engine/concerns/soft_deletable.rb +30 -0
  84. data/app/models/dbdoc_engine/db_design_changelog.rb +44 -0
  85. data/app/models/dbdoc_engine/db_design_dynamic_column.rb +211 -0
  86. data/app/models/dbdoc_engine/db_design_dynamic_table.rb +124 -0
  87. data/app/models/dbdoc_engine/db_design_table_group.rb +88 -0
  88. data/app/models/dbdoc_engine/user.rb +21 -0
  89. data/app/queries/dbdoc_engine/admin_dashboard_queries.rb +71 -0
  90. data/app/queries/dbdoc_engine/db_design_changelog_queries.rb +68 -0
  91. data/app/queries/dbdoc_engine/db_design_dynamic_column_queries.rb +37 -0
  92. data/app/queries/dbdoc_engine/db_design_dynamic_table_commands.rb +106 -0
  93. data/app/queries/dbdoc_engine/db_design_dynamic_table_queries.rb +194 -0
  94. data/app/queries/dbdoc_engine/db_design_table_group_queries.rb +154 -0
  95. data/app/services/dbdoc_engine/db_design_dynamic_table_export_service.rb +38 -0
  96. data/app/services/dbdoc_engine/db_design_dynamic_table_handler_service.rb +49 -0
  97. data/app/services/dbdoc_engine/db_design_dynamic_tables_service.rb +21 -0
  98. data/app/services/dbdoc_engine/error_handler_service.rb +43 -0
  99. data/app/services/dbdoc_engine/schema_rb_import_service.rb +194 -0
  100. data/app/services/dbdoc_engine/schema_rb_parser_service.rb +339 -0
  101. data/app/services/dbdoc_engine/table_filter_service.rb +35 -0
  102. data/app/services/dbdoc_engine/table_groups_service.rb +199 -0
  103. data/app/services/dbdoc_engine/table_management_service.rb +192 -0
  104. data/app/views/dbdoc_engine/admin/dashboard/_action_badge.html.erb +11 -0
  105. data/app/views/dbdoc_engine/admin/dashboard/_changelog_rows.html.erb +22 -0
  106. data/app/views/dbdoc_engine/admin/dashboard/_changelog_table_headers.html.erb +8 -0
  107. data/app/views/dbdoc_engine/admin/dashboard/_filter_fields.html.erb +43 -0
  108. data/app/views/dbdoc_engine/admin/dashboard/index.html.erb +159 -0
  109. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_column_fields.html.erb +225 -0
  110. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_deleted_table_index.html.erb +110 -0
  111. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_foreign_key_fields.html.erb +51 -0
  112. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_form.html.erb +75 -0
  113. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_recent_activity.html.erb +39 -0
  114. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_columns.html.erb +127 -0
  115. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_index.html.erb +109 -0
  116. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_information.html.erb +99 -0
  117. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/deleted_tables.html.erb +95 -0
  118. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/edit.html.erb +23 -0
  119. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/export_all_to_excel.xlsx.axlsx +240 -0
  120. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/export_to_excel.xlsx.axlsx +135 -0
  121. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/index.html.erb +109 -0
  122. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/new.html.erb +25 -0
  123. data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/show_table_info.html.erb +125 -0
  124. data/app/views/dbdoc_engine/admin/db_design_table_groups/_deleted_table_groups_list.html.erb +75 -0
  125. data/app/views/dbdoc_engine/admin/db_design_table_groups/_form.html.erb +88 -0
  126. data/app/views/dbdoc_engine/admin/db_design_table_groups/_table_groups_list.html.erb +82 -0
  127. data/app/views/dbdoc_engine/admin/db_design_table_groups/deleted_groups.html.erb +60 -0
  128. data/app/views/dbdoc_engine/admin/db_design_table_groups/edit.html.erb +25 -0
  129. data/app/views/dbdoc_engine/admin/db_design_table_groups/index.html.erb +85 -0
  130. data/app/views/dbdoc_engine/admin/db_design_table_groups/new.html.erb +26 -0
  131. data/app/views/dbdoc_engine/db_doc_sessions/new.html.erb +59 -0
  132. data/app/views/dbdoc_engine/home/changelog_details.html.erb +80 -0
  133. data/app/views/dbdoc_engine/home/changelogs.html.erb +20 -0
  134. data/app/views/dbdoc_engine/home/group_details.html.erb +94 -0
  135. data/app/views/dbdoc_engine/home/index.html.erb +11 -0
  136. data/app/views/dbdoc_engine/home/partials/_action_badge.html.erb +11 -0
  137. data/app/views/dbdoc_engine/home/partials/_breadcrumb_navigation.html.erb +30 -0
  138. data/app/views/dbdoc_engine/home/partials/_changelog_rows.html.erb +35 -0
  139. data/app/views/dbdoc_engine/home/partials/_changelog_table_headers.html.erb +16 -0
  140. data/app/views/dbdoc_engine/home/partials/_column_headers.html.erb +23 -0
  141. data/app/views/dbdoc_engine/home/partials/_column_row.html.erb +157 -0
  142. data/app/views/dbdoc_engine/home/partials/_filter_form.html.erb +47 -0
  143. data/app/views/dbdoc_engine/home/partials/_group_section.html.erb +84 -0
  144. data/app/views/dbdoc_engine/home/partials/_pagination.html.erb +5 -0
  145. data/app/views/dbdoc_engine/home/partials/_stats_container.html.erb +46 -0
  146. data/app/views/dbdoc_engine/home/partials/_table_groups.html.erb +7 -0
  147. data/app/views/dbdoc_engine/home/partials/_table_information_section.html.erb +50 -0
  148. data/app/views/dbdoc_engine/home/partials/_table_section.html.erb +48 -0
  149. data/app/views/dbdoc_engine/home/table_details.html.erb +9 -0
  150. data/app/views/dbdoc_engine/schema_diagram/index.html.erb +102 -0
  151. data/app/views/dbdoc_engine/shared/_admin_header.html.erb +78 -0
  152. data/app/views/dbdoc_engine/shared/_header.html.erb +94 -0
  153. data/app/views/dbdoc_engine/shared/_js_translations.html.erb +3 -0
  154. data/app/views/dbdoc_engine/shared/_language_button.html.erb +14 -0
  155. data/app/views/dbdoc_engine/shared/_sidebar.html.erb +128 -0
  156. data/app/views/kaminari/dbdoc_engine/_first_page.html.erb +3 -0
  157. data/app/views/kaminari/dbdoc_engine/_gap.html.erb +3 -0
  158. data/app/views/kaminari/dbdoc_engine/_last_page.html.erb +3 -0
  159. data/app/views/kaminari/dbdoc_engine/_next_page.html.erb +3 -0
  160. data/app/views/kaminari/dbdoc_engine/_page.html.erb +9 -0
  161. data/app/views/kaminari/dbdoc_engine/_paginator.html.erb +17 -0
  162. data/app/views/kaminari/dbdoc_engine/_prev_page.html.erb +3 -0
  163. data/app/views/layouts/dbdoc_engine/application.html.erb +107 -0
  164. data/app/views/layouts/dbdoc_engine/header.html.erb +108 -0
  165. data/config/importmap.rb +11 -0
  166. data/config/locales/en.yml +307 -0
  167. data/config/locales/ja.yml +306 -0
  168. data/config/routes.rb +73 -0
  169. data/db/migrate/rails7/20250227060610_create_db_design_table_groups.rb +15 -0
  170. data/db/migrate/rails7/20250227094626_create_db_design_dynamic_tables.rb +19 -0
  171. data/db/migrate/rails7/20250228022732_create_db_design_dynamic_columns.rb +34 -0
  172. data/db/migrate/rails7/20250401051453_create_db_design_changelogs.rb +26 -0
  173. data/db/migrate/rails7/20250411040822_create_users.rb +14 -0
  174. data/db/migrate/rails7/20250421080851_add_missing_indexes_to_dbdoc_tables.rb +23 -0
  175. data/db/migrate/rails8/20250227060610_create_db_design_table_groups.rb +15 -0
  176. data/db/migrate/rails8/20250227094626_create_db_design_dynamic_tables.rb +19 -0
  177. data/db/migrate/rails8/20250228022732_create_db_design_dynamic_columns.rb +34 -0
  178. data/db/migrate/rails8/20250401051453_create_db_design_changelogs.rb +26 -0
  179. data/db/migrate/rails8/20250411040822_create_users.rb +14 -0
  180. data/db/migrate/rails8/20250421080851_add_missing_indexes_to_dbdoc_tables.rb +23 -0
  181. data/db/seeds.rb +28 -0
  182. data/lib/dbdoc_engine/engine.rb +57 -0
  183. data/lib/dbdoc_engine/version.rb +3 -0
  184. data/lib/dbdoc_engine.rb +9 -0
  185. data/lib/generators/dbdoc_engine/install/install_generator.rb +245 -0
  186. data/lib/generators/dbdoc_engine/uninstall/uninstall_generator.rb +196 -0
  187. data/lib/tasks/dbdoc_engine_tasks.rake +44 -0
  188. data/public/dbdoc_engine_assets/images/camel_chess_head.png +0 -0
  189. data/public/dbdoc_engine_assets/images/dblogo.svg +4 -0
  190. data/public/dbdoc_engine_assets/images/japan_circle.png +0 -0
  191. data/public/dbdoc_engine_assets/images/king_chess_head.png +0 -0
  192. data/public/dbdoc_engine_assets/images/login-bg.svg +44 -0
  193. data/public/dbdoc_engine_assets/images/logo.png +0 -0
  194. data/public/dbdoc_engine_assets/images/logo.svg +12 -0
  195. data/public/dbdoc_engine_assets/images/queen_chess_head.png +0 -0
  196. data/public/dbdoc_engine_assets/images/soldier_chess_headd.png +0 -0
  197. data/public/dbdoc_engine_assets/images/uk_circle_transparent.png +0 -0
  198. metadata +415 -0
@@ -0,0 +1,16 @@
1
+ # Dashbord controller
2
+ module DbdocEngine
3
+ class Admin::DashboardController < Admin::BaseController
4
+ def index
5
+ @groups_count = AdminDashboardQueries.groups_count
6
+ @tables_count = AdminDashboardQueries.tables_count
7
+ @columns_count = AdminDashboardQueries.columns_count
8
+
9
+ # Get last 10 changes (no pagination)
10
+ @changelogs = AdminDashboardQueries.filtered_changelogs(params).limit(10)
11
+
12
+ # Prepare detailed chart data
13
+ @chart_data = AdminDashboardQueries.prepare_chart_data(@changelogs)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,63 @@
1
+ module DbdocEngine
2
+ class Admin::DataTransferController < Admin::BaseController
3
+ skip_before_action :verify_authenticity_token, only: [ :import_data, :import_schema ]
4
+
5
+ def export_data
6
+ data = {
7
+ groups: DbDesignTableGroup.where(deleted_at: nil).as_json,
8
+ tables: DbDesignDynamicTable.where(deleted_at: nil).as_json,
9
+ columns: DbDesignDynamicColumn.joins(:db_design_dynamic_table)
10
+ .where(db_design_dynamic_tables: { deleted_at: nil })
11
+ .as_json
12
+ }
13
+ render json: data
14
+ end
15
+
16
+ def import_data
17
+ json_data = JSON.parse(request.body.read)
18
+ ActiveRecord::Base.transaction do
19
+ DbDesignDynamicColumn.unscoped.delete_all
20
+ DbDesignDynamicTable.unscoped.delete_all
21
+ DbDesignTableGroup.unscoped.delete_all
22
+
23
+ DbDesignTableGroup.insert_all!(json_data["groups"]) if json_data["groups"].present?
24
+ DbDesignDynamicTable.insert_all!(json_data["tables"]) if json_data["tables"].present?
25
+ DbDesignDynamicColumn.insert_all!(json_data["columns"]) if json_data["columns"].present?
26
+ end
27
+ render json: { status: "ok" }
28
+ rescue => e
29
+ render json: { status: "error", error: e.message }, status: :unprocessable_entity
30
+ end
31
+
32
+ def import_schema
33
+ schema_content = resolve_schema_content
34
+ result = SchemaRbImportService.new(
35
+ schema_content,
36
+ imported_by: current_user&.username || "system"
37
+ ).import!
38
+
39
+ if result[:status] == "ok"
40
+ render json: { status: "ok", tables_count: result[:tables_count] }
41
+ else
42
+ render json: { status: "error", error: result[:error] }, status: :unprocessable_entity
43
+ end
44
+ rescue => e
45
+ render json: { status: "error", error: e.message }, status: :unprocessable_entity
46
+ end
47
+
48
+ private
49
+
50
+ def resolve_schema_content
51
+ source = params[:source]
52
+
53
+ if source == "project"
54
+ schema_path = Rails.root.join("db", "schema.rb")
55
+ raise "schema.rb not found at #{schema_path}" unless File.exist?(schema_path)
56
+
57
+ File.read(schema_path)
58
+ else
59
+ request.body.read
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,198 @@
1
+ # Controller for managing dynamic tables
2
+ module DbdocEngine
3
+ class Admin::DbDesignDynamicTablesController < Admin::BaseController
4
+ before_action :require_admin, only: %i[new create edit update destroy]
5
+ before_action :require_superadmin, only: [ :deleted_tables ]
6
+ before_action :set_table, only: %i[edit update destroy restore permanent_destroy]
7
+ before_action :load_groups, only: %i[index deleted_tables]
8
+
9
+ # Displays all dynamic tables with filters and pagination
10
+ def index
11
+ @tables = DbdocEngine::DbDesignDynamicTableQueries.all_tables_ordered_by_group
12
+ load_filtered_tables(params[:page])
13
+ @total_table_count = DbdocEngine::DbDesignDynamicTableQueries.count_all_tables
14
+ end
15
+
16
+ # Displays deleted tables with filters and pagination
17
+ def deleted_tables
18
+ @tables = DbdocEngine::DbDesignDynamicTableQueries.all_deleted_tables_with_columns_and_groups
19
+ load_filtered_tables(params[:page])
20
+ @total_table_count = DbdocEngine::DbDesignDynamicTableQueries.count_all_deleted_tables
21
+ end
22
+
23
+ def show_table_info
24
+ @table = DbdocEngine::DbDesignDynamicTableQueries.find_table_with_columns_and_group(params[:id])
25
+ @total_columns_count = @table.db_design_dynamic_columns.size
26
+ @columns = @table.db_design_dynamic_columns.order(is_primary_key: :desc, column_name: :asc).page(params[:page]).per(10)
27
+ table_name = @table.table_name
28
+ @recent_changelogs = DbdocEngine::DbDesignChangelog.where(
29
+ (DbdocEngine::DbDesignChangelog.arel_table[:entity_type].eq("table")
30
+ .and(DbdocEngine::DbDesignChangelog.arel_table[:entity_name].eq(table_name)))
31
+ .or(
32
+ DbdocEngine::DbDesignChangelog.arel_table[:entity_type].eq("column")
33
+ .and(DbdocEngine::DbDesignChangelog.arel_table[:entity_name].matches("#{table_name}.%"))
34
+ )
35
+ ).order(change_timestamp: :desc).limit(10)
36
+ end
37
+
38
+ # Initializes a new table with associated columns
39
+ def new
40
+ @table = DbDesignDynamicTable.new
41
+ @table.db_design_dynamic_columns.build
42
+ load_other_tables
43
+ end
44
+
45
+ # Creates a new dynamic table using the service layer
46
+ def create
47
+ DbDesignDynamicTableHandlerService.new(self, table_params).create
48
+ end
49
+
50
+ # Edits an existing dynamic table
51
+ def edit
52
+ @other_tables = DbdocEngine::DbDesignDynamicTableQueries.find_all_except(@table.id)
53
+ end
54
+
55
+ # Updates an existing dynamic table using the service layer
56
+ def update
57
+ DbDesignDynamicTableHandlerService.new(self, table_params, @table).update
58
+ end
59
+
60
+ # Deletes a table (soft delete)
61
+ def destroy
62
+ handle_table_action(:soft_delete, @table.table_name, I18n.t("dbdoc.table_deletion"),
63
+ admin_db_design_dynamic_tables_path)
64
+ end
65
+
66
+ # Permanently deletes a table
67
+ def permanent_destroy
68
+ handle_table_action(:permanent_destroy, @table.table_name, I18n.t("dbdoc.table_permanent_deletion"),
69
+ deleted_tables_admin_db_design_dynamic_tables_path)
70
+ end
71
+
72
+ # Restores a soft-deleted table
73
+ def restore
74
+ handle_table_action(:restore, @table.table_name, I18n.t("dbdoc.table_restore"),
75
+ deleted_tables_admin_db_design_dynamic_tables_path)
76
+ end
77
+
78
+ # Renders additional column fields dynamically
79
+ def render_column_fields
80
+ @index = params[:index] || Time.now.to_i
81
+ @column = DbDesignDynamicColumn.new
82
+ current_table_id = params[:table_id]
83
+ @other_tables = if current_table_id
84
+ DbdocEngine::DbDesignDynamicTableQueries.find_all_except(current_table_id)
85
+ else
86
+ DbdocEngine::DbDesignDynamicTableQueries.all_tables_with_columns_and_groups
87
+ end
88
+
89
+ render partial: "column_fields", locals: { f: fields_for_column(@column, @index),
90
+ table: @table,
91
+ other_tables: @other_tables }
92
+ end
93
+
94
+ # Checks if a column is referenced in other tables
95
+ def check_column_dependency
96
+ table = DbdocEngine::DbDesignDynamicTableQueries.find_table_with_deleted(params[:table_id])
97
+ is_referenced = DbdocEngine::DbDesignDynamicTableQueries.check_column_is_referenced(
98
+ table.table_name,
99
+ params[:column_name],
100
+ only_active: true
101
+ )
102
+
103
+ render json: { is_referenced: is_referenced }
104
+ end
105
+
106
+ # Fetches columns of a table in JSON format
107
+ def columns
108
+ table = DbdocEngine::DbDesignDynamicTableQueries.find_by_table_name(params[:table_name])
109
+ render json: table ? table.db_design_dynamic_columns.select(:id, :column_name) : []
110
+ end
111
+
112
+ # Exports table data to Excel
113
+ def export_to_excel
114
+ DbDesignDynamicTableExportService.new(params, self).export_single
115
+ end
116
+
117
+ # Exports all tables data to Excel
118
+ def export_all_to_excel
119
+ DbDesignDynamicTableExportService.new(params, self).export_all
120
+ end
121
+
122
+ private
123
+
124
+ # Loads and filters tables with pagination
125
+ def load_filtered_tables(page)
126
+ @tables = TableFilterService.new(@tables, params).filter
127
+ @total_group_count = DbdocEngine::DbDesignTableGroupQueries.count_all_groups
128
+ @tables = @tables.page(page).per(10)
129
+ end
130
+
131
+ # Handles table actions (delete, restore, etc.)
132
+ def handle_table_action(action, table_name, action_description, redirect_path)
133
+ service = TableManagementService.new(@table)
134
+ result = service.send(action)
135
+
136
+ if result[:success]
137
+ success_flash(I18n.t("dbdoc.success.table_action", table_name: table_name, action_description: action_description))
138
+ else
139
+ error_flash(result[:errors].first)
140
+ end
141
+ redirect_to redirect_path
142
+ end
143
+
144
+ # Sets success flash message
145
+ def success_flash(message)
146
+ flash[:notice] = "✅ #{message}"
147
+ end
148
+
149
+ # Sets error flash message
150
+ def error_flash(message)
151
+ flash[:alert] = "❌ #{message}"
152
+ end
153
+
154
+ # Loads table groups for filtering
155
+ def load_groups
156
+ @groups = DbdocEngine::DbDesignTableGroupQueries.select_all_groups
157
+ end
158
+
159
+ # Loads other tables for references
160
+ def load_other_tables
161
+ @other_tables = DbdocEngine::DbDesignDynamicTableQueries.all_tables_with_columns_and_groups
162
+ end
163
+
164
+ # Handles error processing
165
+ def handle_errors(table, result)
166
+ error_handler = ErrorHandlerService.new(table, result)
167
+ error_handler.process_errors
168
+ end
169
+
170
+ # Finds a table, including soft-deleted ones
171
+ def set_table
172
+ @table = DbdocEngine::DbDesignDynamicTableQueries.find_table_with_deleted(params[:id])
173
+ end
174
+
175
+ # Strong parameters for dynamic table creation
176
+ def table_params
177
+ params.require(:db_design_dynamic_table).permit(
178
+ :table_name, :physical_table_name, :db_design_table_group_id, :description, :created_by, :updated_by,
179
+ db_design_dynamic_columns_attributes: %i[
180
+ id column_name physical_column_name data_type length decimal_precision
181
+ is_primary_key is_foreign_key foreign_table_name foreign_column_name relationship_type
182
+ is_candidate_key is_unique_key is_indexed not_null default_value sample_value
183
+ description created_by _destroy
184
+ ]
185
+ )
186
+ end
187
+
188
+ # Generates form fields for columns
189
+ def fields_for_column(column, index)
190
+ ActionView::Helpers::FormBuilder.new(
191
+ "db_design_dynamic_table[db_design_dynamic_columns_attributes][#{index}]",
192
+ column,
193
+ view_context,
194
+ {}
195
+ )
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,107 @@
1
+ # Controller for managing table groups in the admin panel.
2
+ # It provides CRUD operations, soft deletion, restoration, and permanent deletion.
3
+ module DbdocEngine
4
+ class Admin::DbDesignTableGroupsController < Admin::BaseController
5
+ before_action :require_admin, only: %i[new create edit update destroy]
6
+ before_action :require_superadmin, only: [:deleted_groups]
7
+ before_action :set_table_group, only: %i[edit update destroy restore permanent_destroy]
8
+
9
+ # Displays table groups with optional search and deleted items filtering.
10
+ def index
11
+ @search_query = params[:search]
12
+ showing_deleted = params[:show_deleted] == 'true'
13
+
14
+ @table_groups = DbdocEngine::DbDesignTableGroupQueries.search_all_groups(@search_query, showing_deleted)
15
+ @table_groups = @table_groups.page(params[:page]).per(10)
16
+ @showing_deleted = showing_deleted
17
+ end
18
+
19
+ # Displays only soft-deleted table groups.
20
+ def deleted_groups
21
+ @search_query = params[:search]
22
+ @table_groups = DbdocEngine::DbDesignTableGroupQueries.search_deleted_groups(@search_query)
23
+ @table_groups = @table_groups.page(params[:page]).per(10)
24
+ end
25
+
26
+ # Renders form for creating a new table group.
27
+ def new
28
+ @table_group = DbDesignTableGroup.new
29
+ end
30
+
31
+ # Creates a new table group.
32
+ def create
33
+ result = TableGroupsService.new(params).create_group
34
+
35
+ if result[:success]
36
+ flash[:notice] = result[:message]
37
+ redirect_to admin_db_design_table_groups_path
38
+ else
39
+ flash[:alert] = result[:message]
40
+ @table_group = result[:table_group]
41
+ render :new, status: :unprocessable_entity
42
+ end
43
+ end
44
+
45
+ # Renders form for editing an existing table group.
46
+ def edit; end
47
+
48
+ # Updates an existing table group.
49
+ def update
50
+ result = TableGroupsService.new(params).update_group(@table_group)
51
+
52
+ if result[:success]
53
+ flash[:notice] = result[:message]
54
+ redirect_to admin_db_design_table_groups_path
55
+ else
56
+ flash[:alert] = result[:message]
57
+ render :edit, status: :unprocessable_entity
58
+ end
59
+ end
60
+
61
+ # Soft deletes a table group.
62
+ def destroy
63
+ result = TableGroupsService.new(params).delete_group(@table_group)
64
+
65
+ if result[:success]
66
+ flash[:notice] = result[:message]
67
+ else
68
+ flash[:alert] = result[:errors].join(', ')
69
+ end
70
+
71
+ redirect_to admin_db_design_table_groups_path
72
+ end
73
+
74
+ # Restores a soft-deleted table group.
75
+ def restore
76
+ result = TableGroupsService.new(params).restore_group(@table_group)
77
+
78
+ if result[:success]
79
+ flash[:notice] = result[:message]
80
+ else
81
+ flash[:alert] = result[:errors].join(', ')
82
+ end
83
+
84
+ redirect_to deleted_groups_admin_db_design_table_groups_path(show_deleted: true)
85
+ end
86
+
87
+ # Permanently deletes a table group.
88
+ def permanent_destroy
89
+ result = TableGroupsService.new(params).permanent_delete_group(@table_group)
90
+
91
+ if result[:success]
92
+ flash[:notice] = result[:message]
93
+ else
94
+ flash[:alert] = result[:errors].join(', ')
95
+ end
96
+
97
+ redirect_to deleted_groups_admin_db_design_table_groups_path(show_deleted: true)
98
+ end
99
+
100
+ private
101
+
102
+ # Finds the table group, including soft-deleted ones.
103
+ def set_table_group
104
+ @table_group = DbdocEngine::DbDesignTableGroupQueries.find_with_deleted(params[:id])
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,65 @@
1
+ # The ApplicationController serves as the base controller for all other controllers in the application.
2
+ # It includes shared behavior such as internationalization, authentication helpers,
3
+ # browser compatibility enforcement, and global data loading.
4
+ module DbdocEngine
5
+ class ApplicationController < ActionController::Base
6
+ # Makes the following methods available to views:
7
+ # - current_user: returns the currently logged-in user
8
+ # - user_signed_in?: checks if a user is signed in
9
+ # - require_authentication: ensures a user is authenticated
10
+ helper_method :current_user, :user_signed_in?, :require_authentication
11
+
12
+ # Includes language-switching functionality
13
+ include DbdocEngine::Concerns::Internationalization
14
+
15
+ # Only allows modern browsers that support key modern web features such as:
16
+ # - WebP images, Web Push, App Badges, Import Maps
17
+ # - CSS nesting and the :has() pseudo-class
18
+ # allow_browser versions: :modern
19
+
20
+ # Loads table groups and their dynamic tables before every controller action
21
+ before_action :load_groups
22
+
23
+ private
24
+
25
+ # Returns the currently logged-in user, or nil if not logged in.
26
+ def current_user
27
+ @current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
28
+ end
29
+
30
+ # Returns true if a user is signed in, false otherwise.
31
+ def user_signed_in?
32
+ current_user.present?
33
+ end
34
+
35
+ # Ensures the user is authenticated.
36
+ # Redirects to the login page with an alert if not signed in.
37
+ def require_authentication
38
+ return if user_signed_in?
39
+
40
+ redirect_to login_path, alert: "You must log in to access this page"
41
+ end
42
+
43
+ # Ensures the user is an admin or higher.
44
+ # Redirects to the login page with an alert if not authorized.
45
+ def require_admin
46
+ return if user_signed_in? && current_user.admin_or_higher?
47
+
48
+ redirect_to login_path, alert: "You must be an admin to access this page"
49
+ end
50
+
51
+ # Ensures the user is a superadmin.
52
+ # Redirects to the login page with an alert if not authorized.
53
+ def require_superadmin
54
+ return if user_signed_in? && current_user.superadmin?
55
+
56
+ redirect_to login_path, alert: "You must be a superadmin to access this page"
57
+ end
58
+
59
+ # Loads all table groups and their associated dynamic tables.
60
+ # This is made available globally through @groups, often used in layouts or sidebars.
61
+ def load_groups
62
+ @groups = DbDesignTableGroup.includes(:db_design_dynamic_tables).all
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,57 @@
1
+ # app/controllers/concerns/internationalization.rb
2
+ module DbdocEngine::Concerns::Internationalization
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_action :set_locale
7
+ end
8
+
9
+ private
10
+
11
+ def set_locale
12
+ # Find the locale from params, session, cookie, or default
13
+ I18n.locale = find_locale
14
+
15
+ # Store locale in session and cookie
16
+ session[:locale] = I18n.locale
17
+ cookies.signed[:user_locale] = {
18
+ value: I18n.locale,
19
+ expires: 2.weeks.from_now,
20
+ httponly: false # Allow JavaScript access
21
+ }
22
+
23
+ # Set HTML lang attribute value
24
+ @html_lang = I18n.locale
25
+ end
26
+
27
+ def find_locale
28
+ locale_from_params ||
29
+ locale_from_session ||
30
+ locale_from_cookie ||
31
+ I18n.default_locale
32
+ end
33
+
34
+ def locale_from_params
35
+ locale = params[:locale]
36
+ valid_locale?(locale) ? locale : nil
37
+ end
38
+
39
+ def locale_from_session
40
+ locale = session[:locale]
41
+ valid_locale?(locale) ? locale : nil
42
+ end
43
+
44
+ def locale_from_cookie
45
+ locale = cookies.signed[:user_locale]
46
+ valid_locale?(locale) ? locale : nil
47
+ end
48
+
49
+ def valid_locale?(locale)
50
+ locale.present? && I18n.available_locales.map(&:to_s).include?(locale.to_s)
51
+ end
52
+
53
+ # Keep locale parameter in URLs
54
+ def default_url_options
55
+ { locale: I18n.locale }
56
+ end
57
+ end
@@ -0,0 +1,33 @@
1
+ # Handles user login and logout functionality
2
+ module DbdocEngine
3
+ class DbDocSessionsController < ApplicationController
4
+ skip_before_action :verify_authenticity_token
5
+ # Renders the login form
6
+ def new
7
+ # Login form
8
+ end
9
+
10
+ # Authenticates the user and starts a session
11
+ def create
12
+ # Find user by username
13
+ user = User.find_by(username: params[:username])
14
+
15
+ # Authenticate user with password
16
+ if user&.authenticate(params[:password])
17
+ # Store user ID in session and redirect to admin dashboard
18
+ session[:user_id] = user.id
19
+ redirect_to root_path, notice: 'Logged in successfully!'
20
+ else
21
+ # Redirect back to login with error message
22
+ redirect_to login_path, notice: '❌ Invalid Username or Password'
23
+ end
24
+ end
25
+
26
+ # Logs out the user by clearing the session
27
+ def destroy
28
+ # Clear session and redirect to home
29
+ session[:user_id] = nil
30
+ redirect_to login_path, notice: 'Logged out!'
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,79 @@
1
+ # Controller for user-facing pages (public area)
2
+ module DbdocEngine
3
+ class HomeController < ApplicationController
4
+ # Use the 'header' layout for all actions in this controller
5
+ layout 'dbdoc_engine/header'
6
+
7
+ # Require user authentication before any action
8
+ before_action :require_authentication
9
+
10
+ # Home page/dashboard
11
+ def index
12
+ # Get total table count
13
+ @table_count = DbdocEngine::DbDesignDynamicTableQueries.count_all_tables
14
+ # Get total column count
15
+ @field_count = DbDesignDynamicColumn.count
16
+ # Get all groups with their tables and columns
17
+ @groups = DbdocEngine::DbDesignTableGroupQueries.all_groups_with_tables_and_columns
18
+ end
19
+
20
+ # Show details for a specific group
21
+ def group_details
22
+ # Find the group with its tables and columns by ID
23
+ @group = DbdocEngine::DbDesignTableGroupQueries.find_group_with_tables_and_columns(params[:id])
24
+
25
+ if @group.nil?
26
+ # If group not found, redirect with alert
27
+ flash[:alert] = 'Table group deleted or does not exist.'
28
+ redirect_to root_path
29
+ else
30
+ # Get table count for this group
31
+ @tables_count = DbdocEngine::DbDesignDynamicTableQueries.count_tables_in_group(@group)
32
+ # Get all groups for sidebar/nav display
33
+ @groups = DbdocEngine::DbDesignTableGroupQueries.all_groups_with_tables_and_columns
34
+ end
35
+ end
36
+
37
+ # Show details for a specific table
38
+ def table_details
39
+ # Find the table with its columns and group by ID
40
+ @table = DbdocEngine::DbDesignDynamicTableQueries.find_table_with_columns_and_group(params[:id])
41
+
42
+ if @table.nil?
43
+ # If table not found, redirect with alert
44
+ flash[:alert] = '❌ Table deleted or does not exist.'
45
+ redirect_to root_path
46
+ else
47
+ @columns_count = @table.db_design_dynamic_columns.size
48
+ # Get the group this table belongs to
49
+ @group = @table.db_design_table_group
50
+ # Get all groups for sidebar/nav display
51
+ @groups = DbdocEngine::DbDesignTableGroupQueries.all_groups_with_tables_and_columns
52
+ end
53
+ end
54
+
55
+ # Show paginated changelogs with optional filters
56
+ def changelogs
57
+ # Get filtered changelogs based on params
58
+ @changelogs = DbdocEngine::DbDesignChangelogQueries.filtered_changelogs(params)
59
+ # Paginate changelogs (7 per page)
60
+ @changelogs = @changelogs.page(params[:page]).per(7)
61
+ # Get all groups for sidebar/nav display
62
+ @groups = DbdocEngine::DbDesignTableGroupQueries.all_groups_with_tables_and_columns
63
+ end
64
+
65
+ # Show details for a specific changelog entry
66
+ def changelog_details
67
+ # Find the changelog entry by ID
68
+ @changelog = DbdocEngine::DbDesignChangelogQueries.find_changelog(params[:id])
69
+ if @changelog.nil?
70
+ # If not found, redirect with alert
71
+ flash[:alert] = 'Changelog entry not found.'
72
+ redirect_to changelogs_path
73
+ else
74
+ # Get all groups for sidebar/nav display
75
+ @groups = DbdocEngine::DbDesignTableGroupQueries.all_groups_with_tables_and_columns
76
+ end
77
+ end
78
+ end
79
+ end