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,109 @@
1
+ <%= turbo_frame_tag 'tables_results' do %>
2
+ <% if tables.empty? %> <%# Check if there are no tables available %>
3
+ <div class='text-center py-5'>
4
+ <i class='bi bi-search fs-1 text-muted mb-3'></i>
5
+ <h5 class='text-muted'><%= t('dbdoc.no_tables_found') %></h5>
6
+ <% if params[:search].present? || params[:group_filter].present? %>
7
+ <%# Show a message with a link to view all tables if search or filter is applied %>
8
+ <p class='text-muted'><small><%= t('dbdoc.try_different_criteria') %><%= link_to t('dbdoc.view_all_tables'), dbdoc_engine.admin_db_design_dynamic_tables_path %></small></p>
9
+ <% else %>
10
+ <%# If no search or filter is applied, prompt the user to create a new table %>
11
+ <p class='text-muted'><small><%= t('dbdoc.get_started_by_creating_new_table') %></small></p>
12
+ <% end %>
13
+ </div>
14
+ <% else %> <%# If there are tables available, display them in a table format %>
15
+ <div class='card card-custom shadow mb-4'>
16
+ <div class='card-body p-0'>
17
+ <div class='table-responsive p-1'>
18
+ <table class='table mb-0 fs-6'>
19
+ <thead class='table-secondary bg-light'>
20
+ <tr>
21
+ <th class='text-custom-secondary' width="20%"><small><i class='bi bi-folder me-2'></i><%= t('dbdoc.table_group') %></small></th>
22
+ <th class='text-custom-secondary' width="20%"><small><%= t('dbdoc.table_name') %></small></th>
23
+ <th class='text-custom-secondary' width="20%"><small><%= t('dbdoc.physical_name') %></small></th>
24
+ <th class='text-custom-secondary' width="20%"><small><%= t('dbdoc.columns') %></small></th>
25
+ <th class='text-custom-secondary' width="20%"><small><%= t('dbdoc.description') %></small></th>
26
+ <th class='text-custom-secondary' width="20%"><small><%= t('dbdoc.actions') %></small></th>
27
+ </tr>
28
+ </thead>
29
+ <tbody>
30
+ <% grouped_tables = tables.group_by(&:db_design_table_group) %> <%# Group tables by their respective table groups %>
31
+ <% grouped_tables.each do |group, tables| %>
32
+ <% tables.each_with_index do |table, index| %>
33
+ <tr>
34
+ <% if index == 0 %> <%# Only display the group name in the first row of the group %>
35
+ <td class='fw-medium border-end bg-light bg-opacity-25' rowspan='<%= tables.length %>'>
36
+ <% if group %>
37
+ <%# Display the group name and color indicator with table count in brackets %>
38
+ <div class='d-flex align-items-center'>
39
+ <span class='me-2 rounded-circle colour-circle' style='background-color: <%= group.group_color %>;'></span>
40
+ <span>
41
+ <small><%= group.group_name %> (<%= tables.size %>)</small>
42
+ </span>
43
+ </div>
44
+ <% end %>
45
+ </td>
46
+ <% end %>
47
+ <%# Display table name only %>
48
+ <td class='fw-medium'>
49
+ <small><%= link_to table.table_name, dbdoc_engine.show_table_info_admin_db_design_dynamic_table_path(table), class: 'text-decoration-none text-custom-primary', data: { turbo_frame: "_top" } %></small>
50
+ </td>
51
+ <%# Display physical table name in a separate column %>
52
+ <td class='text-muted'>
53
+ <%= link_to dbdoc_engine.show_table_info_admin_db_design_dynamic_table_path(table), class: 'text-decoration-none text-muted', data: { turbo_frame: "_top" } do %>
54
+ <small><%= table.physical_table_name %></small>
55
+ <% end %>
56
+ </td>
57
+ <%# Display the number of columns in the table %>
58
+ <td>
59
+ <span>
60
+ <small><%= table.db_design_dynamic_columns.size %></small>
61
+ </span>
62
+ </td>
63
+ <%# Display table description with truncation and tooltip %>
64
+ <td>
65
+ <div class='description-text truncate-by-width' data-bs-toggle="tooltip" title="<%= table.description %>">
66
+ <small><%= table.description %></small>
67
+ </div>
68
+ </td>
69
+ <%# Display action buttons right-aligned: Edit, Export to Excel, Delete %>
70
+ <td>
71
+ <div class='d-flex justify-content-end gap-2'>
72
+ <% if can_edit? %>
73
+ <%# Edit button %>
74
+ <%= link_to dbdoc_engine.edit_admin_db_design_dynamic_table_path(table), class: 'btn btn-outline-warning btn-sm px-2 shadow-sm', data: { turbo_frame: '_top' } do %>
75
+ <small><i class='bi bi-pencil-square'></i></small>
76
+ <% end %>
77
+ <% end %>
78
+ <%# Export to Excel button with download icon %>
79
+ <%= link_to dbdoc_engine.export_to_excel_admin_db_design_dynamic_table_path(table, format: :xlsx),
80
+ class: 'btn btn-outline-primary btn-sm px-2 shadow-sm',
81
+ target: '_blank',
82
+ data: { turbo: false } do %>
83
+ <small><i class='bi bi-download'></i></small>
84
+ <% end %>
85
+ <% if can_edit? %>
86
+ <%# Delete button with confirmation prompt %>
87
+ <%= button_to dbdoc_engine.admin_db_design_dynamic_table_path(table),
88
+ method: :delete,
89
+ data: { confirm: 'Are you sure?', turbo: false },
90
+ class: 'btn btn-outline-danger btn-sm px-2 shadow-sm' do %>
91
+ <small><i class='bi bi-trash-fill'></i></small>
92
+ <% end %>
93
+ <% end %>
94
+ </div>
95
+ </td>
96
+ </tr>
97
+ <% end %>
98
+ <% end %>
99
+ </tbody>
100
+ </table>
101
+ <%# Pagination for the tables list %>
102
+ <div class='d-flex mt-3 justify-content-end p-3'>
103
+ <small><%= paginate tables, theme: 'dbdoc_engine' %></small>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ <% end %>
109
+ <% end %>
@@ -0,0 +1,99 @@
1
+ <%# This partial renders the basic table information form section Including table name, physical name, group, description, etc.%>
2
+ <div class='card mb-4 shadow'>
3
+ <div class='card-header bg-light '>
4
+ <h3 class='mb-0 fs-5'><%= t('dbdoc.table_information') %></h3>
5
+ </div>
6
+ <div class='card-body'>
7
+ <%# Table name field %>
8
+ <div class='row mb-3'>
9
+ <div class='col-md-3' id='table_table_name'>
10
+ <%= f.label :table_name, t('dbdoc.table_name'), class: 'form-label fw-semibold required-field' %>
11
+ </div>
12
+ <div class='col-md-9'>
13
+ <%= f.text_field :table_name,
14
+ class: "form-control #{'is-invalid' if table.errors[:table_name].any?}" %>
15
+ <% if table.errors[:table_name].any? %>
16
+ <div class='invalid-feedback d-block'>
17
+ <%= table.errors[:table_name].first %>
18
+ </div>
19
+ <% end %>
20
+ </div>
21
+ </div>
22
+ <%# Physical table name field - used in database schema %>
23
+ <div class='row mb-3'>
24
+ <div class='col-md-3' id='table_physical_table_name'>
25
+ <%= f.label :physical_table_name, t('dbdoc.physical_table_name'), class: 'form-label fw-semibold required-field' %>
26
+ </div>
27
+ <div class='col-md-9'>
28
+ <%= f.text_field :physical_table_name,
29
+ class: "form-control #{'is-invalid' if table.errors[:physical_table_name].any?}" %>
30
+ </div>
31
+ </div>
32
+ <%# Table group dropdown for categorizing tables %>
33
+ <div class='row mb-3'>
34
+ <div class='col-md-3' id='table_db_design_table_group_id'>
35
+ <%= f.label :db_design_table_group_id, t('dbdoc.table_group'), class: 'form-label fw-semibold required-field' %>
36
+ </div>
37
+ <div class='col-md-9'>
38
+ <div data-controller="select2" class="<%= 'is-invalid-select2' if table.errors[:db_design_table_group_id].any? %>">
39
+ <%= f.collection_select :db_design_table_group_id,
40
+ DbdocEngine::DbDesignTableGroupQueries.all_groups_for_selection, :id, :group_name,
41
+ { prompt: t('dbdoc.select_table_group') },
42
+ {
43
+ class: "form-select taller-select2 #{'is-invalid' if table.errors[:db_design_table_group_id].any?}",
44
+ data: {
45
+ select2_target: "select",
46
+ select2_placeholder_value: t('dbdoc.select_table_group')
47
+ }
48
+ } %>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ <%# Table description textarea %>
53
+ <div class='row mb-3'>
54
+ <div class='col-md-3'>
55
+ <%= f.label :description, t('dbdoc.description'), class: 'form-label fw-semibold' %>
56
+ </div>
57
+ <div class='col-md-9'>
58
+ <%= f.text_area :description,
59
+ class: "form-control #{'is-invalid' if table.errors[:description].any?}",
60
+ rows: 3 %>
61
+ <% if table.errors[:description].any? %>
62
+ <div class='invalid-feedback d-block'>
63
+ <%= table.errors[:description].first %>
64
+ </div>
65
+ <% end %>
66
+ </div>
67
+ </div>
68
+ <%# Created by field for tracking purposes %>
69
+ <div class='row mb-3'>
70
+ <div class='col-md-3' id='table_created_by'>
71
+ <%= f.label :created_by, t('dbdoc.created_by'), class: 'form-label fw-semibold required-field' %>
72
+ </div>
73
+ <div class='col-md-9'>
74
+ <%= f.text_field :created_by,
75
+ class: "form-control #{'is-invalid' if table.errors[:created_by].any?}",
76
+ data: { table_validation_target: "createdBy" } %>
77
+ </div>
78
+ </div>
79
+ <%# Updated by field - Only show when editing an existing record %>
80
+ <% if table.persisted? %>
81
+ <div class='row mb-3'>
82
+ <div class='col-md-3' id='table_updated_by'>
83
+ <%= f.label :updated_by, t('dbdoc.updated_by'), class: 'form-label fw-semibold required-field' %>
84
+ </div>
85
+ <div class='col-md-9'>
86
+ <%= f.text_field :updated_by,
87
+ value: "",
88
+ class: "form-control #{'is-invalid' if table.errors[:updated_by].any?}",
89
+ data: { table_validation_target: "updatedBy" } %>
90
+ </div>
91
+ </div>
92
+ <% else %>
93
+ <%# Add a hidden field for updated_by when creating a new record %>
94
+ <%= f.hidden_field :updated_by,
95
+ value: f.object.created_by,
96
+ data: { table_validation_target: "updatedBy" } %>
97
+ <% end %>
98
+ </div>
99
+ </div>
@@ -0,0 +1,95 @@
1
+ <!-- Custom Styled Breadcrumbs -->
2
+ <div class='d-flex align-items-center mb-3 breadcrumb-container mt-4 ms-5'>
3
+ <a href='<%= dbdoc_engine.root_path %>' class='text-decoration-none text-muted'>
4
+ <small><i class='bi bi-house-door'></i></small>
5
+ </a>
6
+ <span class='slash'> / </span>
7
+ <a href="<%= dbdoc_engine.admin_dashboard_path(locale: I18n.locale) %>" class='text-decoration-none text-muted'>
8
+ <small><%= t('dbdoc.dashboardbread') %></small>
9
+ </a>
10
+ <span class='slash'> / </span>
11
+ <a href='<%= dbdoc_engine.admin_db_design_dynamic_tables_path %>' class='text-decoration-none text-muted'>
12
+ <small><%= t('dbdoc.dynamic_tables_header') %></small>
13
+ </a>
14
+ <span class='slash'> / </span>
15
+ <small><span class='text-custom-primary fw-medium'><%= t('dbdoc.deletedtables') %></span></small>
16
+ </div>
17
+ <div class='container-fluid mt-4 ps-5 pe-5'>
18
+ <!-- Page Heading with Stats Summary -->
19
+ <div class='mb-4'>
20
+ <div class='d-flex justify-content-between align-items-center'>
21
+ <h4 class='fw-bold mb-0 text-custom-primary mb-4'>
22
+ <%= t('dbdoc.deleted_tables') %>
23
+ </h4>
24
+ </div>
25
+ <!-- Combined Search Filter and Action Button Section -->
26
+ <div class='row mb-3'>
27
+ <!-- Search and Filter Form -->
28
+ <div class='col-lg-8 col-md-7 col-sm-12 mb-2 mb-md-0'>
29
+ <small><%= form_with url: deleted_tables_admin_db_design_dynamic_tables_path, method: :get, data: { controller: 'auto-submit', turbo_frame: 'tables_results' } do |f| %>
30
+ <%= f.hidden_field :locale, value: I18n.locale %>
31
+ <div class='input-group shadow-sm'>
32
+ <!-- Search Icon -->
33
+ <span class='input-group-text bg-white border-end-0'>
34
+ <i class='bi bi-search text-muted'></i>
35
+ </span>
36
+
37
+ <!-- Search Field -->
38
+ <%= f.text_field :search, value: params[:search], class: 'form-control border-start-0', placeholder: t('dbdoc.search_admin'), data: { action: 'input->auto-submit#submit' } %>
39
+
40
+ <!-- Filter Icon -->
41
+ <span class='input-group-text bg-white border-start-0 border-end-0'>
42
+ <i class='bi bi-filter text-muted'></i>
43
+ </span>
44
+
45
+ <!-- Group Filter Dropdown -->
46
+ <%= f.select :group_filter,
47
+ group_filter_options(@groups, params[:group_filter]),
48
+ {},
49
+ { class: 'form-select border-start-0', escape: false, data: { action: 'change->auto-submit#submit' } } %>
50
+
51
+ <!-- Clear Filter Button -->
52
+ <% if params[:search].present? || params[:group_filter].present? %>
53
+ <%= link_to dbdoc_engine.deleted_tables_admin_db_design_dynamic_tables_path, class: 'btn btn-outline-secondary' do %>
54
+ <i class='bi bi-x-circle'></i><%= t('dbdoc.clear') %>
55
+ <% end %>
56
+ <% end %>
57
+ </div>
58
+ <% end %></small>
59
+ </div>
60
+
61
+ <!-- Action Buttons -->
62
+ <div class='col-lg-4 col-md-5 col-sm-12 d-flex justify-content-md-end justify-content-sm-start mt-2 mt-md-0'>
63
+ <!-- Show Active Tables Button -->
64
+ <small><%= link_to dbdoc_engine.admin_db_design_dynamic_tables_path, class: 'btn btn-outline-primary shadow-sm d-flex align-items-center' do %>
65
+ <i class='bi bi-eye-fill me-2'></i><span class="d-none d-sm-inline"><small><%= t('dbdoc.show_active') %></span></small>
66
+ <% end %></small>
67
+ </div>
68
+ </div>
69
+
70
+ <!-- Deleted Tables Turbo Frame -->
71
+ <%= turbo_frame_tag 'tables_results' do %>
72
+ <% if @tables.empty? %>
73
+ <!-- No Tables Message -->
74
+ <div class='text-center py-5'>
75
+ <i class='bi bi-trash fs-1 text-muted mb-3'></i>
76
+ <h5 class='text-muted'><%= t('dbdoc.no_deleted_tables_found') %></h5>
77
+
78
+ <% if params[:search].present? || params[:group_filter].present? %>
79
+ <!-- If filters applied and nothing found -->
80
+ <small><p class='text-muted'>
81
+ <%= t('dbdoc.try_different_criteria') %>
82
+ <%= link_to t('dbdoc.view_all_deleted_tables'), dbdoc_engine.deleted_tables_admin_db_design_dynamic_tables_path %>
83
+ </p></small>
84
+ <% else %>
85
+ <!-- If no deleted tables exist -->
86
+ <small><p class='text-muted'><%= t('dbdoc.no_tables_have_been_deleted') %></p></small>
87
+ <% end %>
88
+ </div>
89
+ <% else %>
90
+ <!-- Render Deleted Tables Partial -->
91
+ <%= render 'deleted_table_index', tables: @tables %>
92
+ <% end %>
93
+ <% end %>
94
+ </div>
95
+ </div>
@@ -0,0 +1,23 @@
1
+ <%# Edit table page view Sets page title and renders the shared form%>
2
+ <% content_for :title, t('dbdoc.edit_table') %>
3
+ <!-- Custom Styled Breadcrumbs -->
4
+ <div class='d-flex align-items-center mb-3 breadcrumb-container mt-4 ms-5'>
5
+ <a href='<%= dbdoc_engine.root_path %>' class='text-decoration-none text-muted'>
6
+ <small><i class='bi bi-house-door'></i></small>
7
+ </a>
8
+ <span class='slash'> / </span>
9
+ <a href="<%= dbdoc_engine.admin_dashboard_path(locale: I18n.locale) %>" class='text-decoration-none text-muted'>
10
+ <small><%= t('dbdoc.dashboardbread') %></small>
11
+ </a>
12
+ <span class='slash'> / </span>
13
+ <a href='<%= dbdoc_engine.admin_db_design_dynamic_tables_path %>' class='text-decoration-none text-muted'>
14
+ <small><%= t('dbdoc.dynamic_tables_header') %></small>
15
+ </a>
16
+ <span class='slash'> / </span>
17
+ <small><span class='text-custom-primary fw-medium'><%= t('dbdoc.edit_table') %></span></small>
18
+ </div>
19
+ <h4 class='fw-bold mt-3 ms-5 mb-2 text-custom-primary'>
20
+ <i class='bi bi-pencil-square me-1'></i><%= t('dbdoc.edit_table') %>
21
+ </h4>
22
+ <%= render 'form', table: @table, other_tables: @other_tables, existing_tables: @existing_tables %>
23
+ <br>
@@ -0,0 +1,240 @@
1
+ # app/views/admin/db_design_dynamic_tables/export_all_to_excel.xlsx.axlsx
2
+ # rubocop:disable Metrics/BlockLength
3
+ wb = xlsx_package.workbook
4
+
5
+ t = ->(key) { I18n.t("dbdoc.excel.#{key}") }
6
+
7
+ # Create Table List sheet first (this will be the first sheet)
8
+ table_list_sheet = wb.add_worksheet(name: t.call("table_list"))
9
+ table_list_sheet.sheet_view.show_grid_lines = false
10
+
11
+ # Create table sheets next
12
+ sheet_references = {}
13
+ @tables.each_with_index do |table, table_idx|
14
+ # Sanitize sheet name for Excel
15
+ safe_name = table.table_name.gsub(%r{[\[\]*?/\\]}, "").truncate(30, omission: "")
16
+ sheet_references[table.id] = safe_name # Store reference to use later
17
+
18
+ wb.add_worksheet(name: safe_name) do |sheet|
19
+ sheet.sheet_view.show_grid_lines = false
20
+ # Styles
21
+ detail_header_style = sheet.styles.add_style(
22
+ bg_color: "FFFF00", # Yellow background
23
+ border: { style: :thin, color: "000000" }
24
+ )
25
+ column_header_style = sheet.styles.add_style(
26
+ bg_color: "FFFFFF",
27
+ b: true,
28
+ border: { style: :medium, color: "000000" },
29
+ alignment: { horizontal: :center, vertical: :center }
30
+ )
31
+ centered_cell_style = sheet.styles.add_style(
32
+ border: { style: :thin, color: "000000" },
33
+ alignment: { horizontal: :center }
34
+ )
35
+ detail_cell_style = sheet.styles.add_style(
36
+ border: { style: :thin, color: "000000" },
37
+ alignment: { horizontal: :left }
38
+ )
39
+ note_header_style = sheet.styles.add_style(
40
+ bg_color: "FFFFFF",
41
+ border: { style: :thin, color: "000000" },
42
+ alignment: { horizontal: :center }
43
+ )
44
+ no_border_style = sheet.styles.add_style(
45
+ bg_color: "FFFFFF"
46
+ )
47
+
48
+ # Table Header Section
49
+ sheet.add_row [ "", t.call("category"), t.call("master") ], style: [ no_border_style, detail_header_style, detail_header_style, detail_header_style, detail_header_style, detail_header_style ]
50
+
51
+ # Table Basic Info
52
+ sheet.rows.size
53
+
54
+ sheet.add_row([ "", t.call("no"), (table_idx + 1).to_s ], style: [ no_border_style, detail_header_style, detail_cell_style ])
55
+ sheet.add_row([ "", t.call("physical_table_name"), table.physical_table_name ], style: [ no_border_style, detail_header_style, detail_cell_style ])
56
+ sheet.add_row([ "", t.call("logical_table_name"), table.table_name ], style: [ no_border_style, detail_header_style, detail_cell_style ])
57
+ sheet.add_row([ "", t.call("version"), "1.0" ], style: [ no_border_style, detail_header_style, detail_cell_style ])
58
+ sheet.add_row([ "", t.call("created_by"), table.created_by ], style: [ no_border_style, detail_header_style, detail_cell_style ])
59
+ sheet.add_row([ "", t.call("created_date"), table.created_at&.strftime("%Y-%m-%d") ], style: [ no_border_style, detail_header_style, detail_cell_style ])
60
+ sheet.add_row([ "", t.call("updated_by"), table.updated_by ], style: [ no_border_style, detail_header_style, detail_cell_style ])
61
+ sheet.add_row([ "", t.call("updated_date"), table.updated_at&.strftime("%Y-%m-%d") ], style: [ no_border_style, detail_header_style, detail_cell_style ])
62
+
63
+ # Empty row
64
+ sheet.add_row []
65
+
66
+ # Note section
67
+ sheet.rows.size
68
+ sheet.add_row([ "", t.call("overview") ], style: [ no_border_style, note_header_style ])
69
+ desc_row = sheet.rows.size + 1
70
+
71
+ note_border_style = sheet.styles.add_style(
72
+ border: { style: :medium, color: "000000" }
73
+ )
74
+
75
+ note_row_data = [ "" ]
76
+ note_row_data += [ table.description.to_s ] + [ "" ] * 12
77
+ sheet.add_row(note_row_data, style: [ no_border_style ] + Array.new(13, note_border_style), height: 20)
78
+
79
+ sheet.merge_cells("B#{desc_row}:N#{desc_row}")
80
+
81
+ # Empty rows
82
+ sheet.add_row []
83
+ sheet.add_row []
84
+
85
+ # First column header row
86
+ first_header_row_styles = Array.new(14, no_border_style)
87
+ first_header_row_styles[3] = column_header_style
88
+ first_header_row_styles[4] = column_header_style
89
+ first_header_row_styles[5] = column_header_style
90
+
91
+ sheet.add_row [
92
+ "", "", "", t.call("data_type"), t.call("length"), t.call("decimal_places"), "", "", "", "", "", "", "", ""
93
+ ], style: first_header_row_styles, height: 20
94
+
95
+ # Column details header
96
+ sheet.add_row [
97
+ "No",
98
+ t.call("logical_column_name"),
99
+ t.call("physical_column_name"),
100
+ t.call("data_type"),
101
+ t.call("length"),
102
+ t.call("decimal_places"),
103
+ t.call("not_null"),
104
+ t.call("default"),
105
+ "PK",
106
+ "FK",
107
+ "CK",
108
+ "UK",
109
+ "INDEX",
110
+ t.call("remark")
111
+ ], style: Array.new(14, column_header_style), height: 40
112
+
113
+ # Column details
114
+ table.db_design_dynamic_columns.each_with_index do |column, col_idx|
115
+ row_styles = Array.new(14, detail_cell_style)
116
+
117
+ (4..12).each do |idx|
118
+ row_styles[idx] = centered_cell_style
119
+ end
120
+
121
+ length_display = column.length.present? ? "#{column.length} bytes" : ""
122
+
123
+ col_data = [
124
+ col_idx + 1,
125
+ column.column_name,
126
+ column.physical_column_name,
127
+ column.data_type,
128
+ length_display,
129
+ column.decimal_precision,
130
+ column.not_null ? "〇" : "",
131
+ column.default_value,
132
+ column.is_primary_key ? "〇" : "",
133
+ column.is_foreign_key ? "〇" : "",
134
+ column.is_candidate_key ? "〇" : "",
135
+ column.is_unique_key ? "〇" : "",
136
+ column.is_indexed ? "〇" : "",
137
+ column.description
138
+ ]
139
+ sheet.add_row col_data, style: row_styles
140
+ end
141
+
142
+ # Set column widths
143
+ sheet.column_widths 5, 25, 30, 30, 15, 15, 20, 10, 5, 5, 5, 5, 10, 40
144
+ end
145
+ end
146
+
147
+ # Now go back and populate the Table List sheet with hyperlinks to individual sheets
148
+ header_style = table_list_sheet.styles.add_style(
149
+ bg_color: "E6F1DE",
150
+ b: true,
151
+ border: { style: :thin, color: "000000" },
152
+ alignment: { horizontal: :center, vertical: :center }
153
+ )
154
+ cell_style = table_list_sheet.styles.add_style(
155
+ border: { style: :thin, color: "000000" }
156
+ )
157
+ active_style = table_list_sheet.styles.add_style(
158
+ border: { style: :thin, color: "000000" },
159
+ alignment: { horizontal: :center, vertical: :center }
160
+ )
161
+ date_style = table_list_sheet.styles.add_style(
162
+ border: { style: :thin, color: "000000" },
163
+ format_code: "yyyy-mm-dd"
164
+ )
165
+ hyperlink_style = table_list_sheet.styles.add_style(
166
+ border: { style: :thin, color: "000000" },
167
+ fg_color: "0000FF",
168
+ u: true
169
+ )
170
+
171
+ # Empty row
172
+ table_list_sheet.add_row []
173
+
174
+ # First header row
175
+ table_list_sheet.add_row [
176
+ "",
177
+ t.call("table_name_header"),
178
+ t.call("table_name_header"),
179
+ t.call("table_header"), t.call("table_header"), t.call("table_header"), t.call("table_header"),
180
+ "", "", "", "", ""
181
+ ], style: header_style
182
+
183
+ table_list_sheet.merge_cells("B2:C2")
184
+ table_list_sheet.merge_cells("D2:G2")
185
+
186
+ # Second header row
187
+ table_list_sheet.add_row [
188
+ "No",
189
+ t.call("logical_name"),
190
+ t.call("physical_name"),
191
+ t.call("history"),
192
+ t.call("backup"),
193
+ t.call("active"),
194
+ t.call("used_by"),
195
+ t.call("created_date"),
196
+ t.call("notes"),
197
+ t.call("verify_date"),
198
+ t.call("verify_by"),
199
+ t.call("verified")
200
+ ], style: header_style
201
+
202
+ # Table rows with hyperlinks
203
+ @tables.each_with_index do |table, table_idx|
204
+ row_data = [
205
+ table_idx + 1,
206
+ table.table_name,
207
+ table.physical_table_name,
208
+ "",
209
+ "",
210
+ "●",
211
+ "",
212
+ table.created_at,
213
+ table.description,
214
+ "",
215
+ "",
216
+ ""
217
+ ]
218
+
219
+ row_styles = Array.new(12, cell_style)
220
+ row_styles[1] = hyperlink_style
221
+ row_styles[5] = active_style
222
+ row_styles[7] = date_style
223
+
224
+ row = table_list_sheet.add_row row_data, style: row_styles
225
+
226
+ sheet_name = sheet_references[table.id]
227
+ next unless sheet_name
228
+
229
+ cell_ref = "B#{row.row_index + 1}"
230
+ table_list_sheet.add_hyperlink(
231
+ location: "#{sheet_name}!A1",
232
+ ref: cell_ref,
233
+ target: :sheet
234
+ )
235
+ end
236
+
237
+ # Column widths
238
+ table_list_sheet.column_widths 5, 20, 20, 10, 10, 10, 25, 15, 40, 15, 15, 15
239
+
240
+ # rubocop:enable Metrics/BlockLength