mensa 0.3.2 → 0.3.3

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +1 -17
  4. data/README.md +16 -42
  5. data/app/components/mensa/add_filter/component.html.erb +31 -0
  6. data/app/components/mensa/cell/component.html.erb +1 -0
  7. data/app/components/mensa/column_customizer/component.html.erb +31 -0
  8. data/app/components/mensa/control_bar/component.html.erb +56 -0
  9. data/app/components/mensa/empty_state/component.html.erb +10 -0
  10. data/app/components/mensa/filter_pill/component.html.erb +20 -0
  11. data/app/components/mensa/filter_pill_list/component.html.erb +30 -0
  12. data/app/components/mensa/header/component.html.erb +12 -0
  13. data/app/components/mensa/row_action/component.html.erb +9 -0
  14. data/app/components/mensa/search/component.html.erb +26 -0
  15. data/app/components/mensa/table/component.html.erb +25 -0
  16. data/app/components/mensa/table_row/component.html.erb +18 -0
  17. data/app/components/mensa/view/component.html.erb +51 -0
  18. data/app/components/mensa/views/component.html.erb +74 -0
  19. data/app/views/mensa/exports/_badge.html.erb +6 -0
  20. data/app/views/mensa/exports/_dialog.html.erb +52 -0
  21. data/app/views/mensa/exports/_list.html.erb +32 -0
  22. data/app/views/mensa/tables/filters/show.turbo_stream.erb +58 -0
  23. data/app/views/mensa/tables/show.html.erb +5 -0
  24. data/app/views/mensa/tables/show.turbo_stream.erb +7 -0
  25. data/app/views/mensa/tables/views/create.turbo_stream.erb +11 -0
  26. data/app/views/mensa/tables/views/destroy.turbo_stream.erb +11 -0
  27. data/app/views/mensa/tables/views/update.turbo_stream.erb +11 -0
  28. data/lib/generators/mensa/table_generator.rb +15 -0
  29. data/lib/generators/mensa/templates/config/initializers/mensa.rb +4 -5
  30. data/lib/generators/mensa/templates/table.rb.tt +18 -0
  31. data/lib/mensa/engine.rb +0 -1
  32. data/lib/mensa/version.rb +1 -1
  33. data/mensa.gemspec +2 -4
  34. metadata +29 -54
  35. data/app/components/mensa/add_filter/component.html.slim +0 -14
  36. data/app/components/mensa/cell/component.html.slim +0 -1
  37. data/app/components/mensa/column_customizer/component.html.slim +0 -14
  38. data/app/components/mensa/control_bar/component.html.slim +0 -43
  39. data/app/components/mensa/empty_state/component.html.slim +0 -7
  40. data/app/components/mensa/filter_pill/component.html.slim +0 -9
  41. data/app/components/mensa/filter_pill_list/component.html.slim +0 -11
  42. data/app/components/mensa/header/component.html.slim +0 -8
  43. data/app/components/mensa/row_action/component.html.slim +0 -6
  44. data/app/components/mensa/search/component.html.slim +0 -21
  45. data/app/components/mensa/table/component.html.slim +0 -10
  46. data/app/components/mensa/table_row/component.html.slim +0 -11
  47. data/app/components/mensa/view/component.html.slim +0 -30
  48. data/app/components/mensa/views/component.html.slim +0 -52
  49. data/app/views/mensa/exports/_badge.html.slim +0 -5
  50. data/app/views/mensa/exports/_dialog.html.slim +0 -42
  51. data/app/views/mensa/exports/_list.html.slim +0 -29
  52. data/app/views/mensa/tables/filters/show.turbo_stream.slim +0 -36
  53. data/app/views/mensa/tables/show.html.slim +0 -4
  54. data/app/views/mensa/tables/show.turbo_stream.slim +0 -5
  55. data/app/views/mensa/tables/views/create.turbo_stream.slim +0 -11
  56. data/app/views/mensa/tables/views/destroy.turbo_stream.slim +0 -11
  57. data/app/views/mensa/tables/views/update.turbo_stream.slim +0 -11
@@ -1,10 +0,0 @@
1
- .mensa-table id="table-#{table.table_id}" data-mensa-table-supports-views-value="#{table.supports_views?}" data-mensa-table-table-url-value=helpers.mensa.table_url(table.name, {turbo_frame_id: table.table_id}.merge(params)) data-mensa-table-save-view-url-value=helpers.mensa.table_views_path(table.name) data-mensa-table-views-url-value=helpers.mensa.table_views_path(table.name) data-mensa-table-exports-url-value=helpers.mensa.table_exports_path(table.name) data-controller="mensa-table" data-mensa-table-mensa-filter-pill-outlet="[data-controller='mensa-filter-pill']" data-mensa-table-mensa-filter-pill-list-outlet="#mensa-filter-pill-list-#{table.table_id}" data-mensa-table-mensa-column-customizer-outlet="[data-controller='mensa-column-customizer']"
2
- .mensa-table__toolbar
3
- .mensa-table__search-container
4
- - if table.supports_views? && table.show_header?
5
- = render Mensa::Views::Component.new(table: table)
6
- div.flex.flex-1.min-w-0 id="filters-#{table.table_id}"
7
- = render Mensa::FilterPillList::Component.new(table: table)
8
- = render Mensa::ControlBar::Component.new(table: table)
9
- = render Mensa::Search::Component.new(table: table)
10
- turbo-frame id=table.table_id target="_top" data-mensa-table-target="turboFrame" data-turbo-permanent=""
@@ -1,11 +0,0 @@
1
- tr *row.link_attributes
2
- - if table. batch_actions?
3
- td.mensa-table__checkbox-col data-action="click->mensa-selection#stopPropagation"
4
- input.mensa-table__select-all type="checkbox" value=row.record.id data-action="change->mensa-selection#toggleRow" data-mensa-selection-target="rowCheckbox"
5
- - if table.actions? && Mensa.config.row_actions_position == :front
6
- td.actions
7
- = render(Mensa::RowAction::Component.with_collection(table.actions, row: row, table: table))
8
- = render(Mensa::Cell::Component.with_collection(table.display_columns, row: row))
9
- - if table.actions? && Mensa.config.row_actions_position == :back
10
- td.actions
11
- = render(Mensa::RowAction::Component.with_collection(table.actions, row: row, table: table))
@@ -1,30 +0,0 @@
1
- .overflow-y-auto.relative data-mensa-table-target="view" data-controller="mensa-selection" data-mensa-selection-batch-url-value=(table.batch_actions? ? helpers.mensa.table_batch_actions_path(table.name) : "")
2
- - if table.batch_actions?
3
- .mensa-batch-bar.hidden data-mensa-selection-target="batchBar"
4
- .mensa-batch-bar__content
5
- input.mensa-table__select-all type="checkbox" data-action="click->mensa-selection#deselectAll" data-mensa-selection-target="batchAllCheckbox"
6
- span.mensa-batch-bar__count data-mensa-selection-target="selectedCount"
7
- - table.batch_actions.each do |batch_action|
8
- button.mensa-batch-bar__button type="button" data-action="click->mensa-selection#executeBatch" data-mensa-selection-batch-action-param=batch_action.name.to_s
9
- = batch_action.title
10
- table.w-full
11
- - if table.show_header?
12
- thead
13
- tr
14
- - if table. batch_actions?
15
- th.mensa-table__checkbox-col
16
- .container
17
- input.mensa-table__select-all type="checkbox" data-action="change->mensa-selection#toggleAll" data-mensa-selection-target="headerCheckbox"
18
- - if table.actions? && Mensa.config.row_actions_position == :front
19
- th Actions
20
- = render(Mensa::Header::Component.with_collection(table.display_columns, table: table))
21
- - if table.actions? && Mensa.config.row_actions_position == :back
22
- th Actions
23
- tbody
24
- = render(Mensa::TableRow::Component.with_collection(table.rows, table: table))
25
- - if table.pagy_details&.count == 0
26
- = render Mensa::EmptyState::Component.new(table: table)
27
- - elsif table.pagy_details&.last > 1
28
- .paging
29
- span = t("mensa.paging.info", model: model_name_plural, from: table.pagy_details.from, to: table.pagy_details.to, count: table.pagy_details.count)
30
- == table.pagy_details.series_nav(anchor_string: 'data-turbo-frame="_self"')
@@ -1,52 +0,0 @@
1
- - current_view = table.all_views.find { |v| v.id == table.table_view&.id } || table.all_views.first
2
- - current_view_name = current_view&.name || t(".all", default: "All")
3
- - current_view_id = current_view&.id || ""
4
-
5
- .mensa-table__views id="mensa-views-#{table.table_id}" data-mensa-table-target="views" data-controller="mensa-views" data-mensa-views-mensa-filter-pill-list-outlet="#mensa-filter-pill-list-#{table.table_id}" data-mensa-views-table-id-value=table.table_id data-mensa-views-views-url-value=helpers.mensa.table_views_path(table.name)
6
- button.mensa-table__views__trigger type="button" data-action="mensa-views#toggleDropdown" data-mensa-views-target="trigger" aria-haspopup="listbox"
7
- span.mensa-table__views__trigger-label data-mensa-views-target="triggerLabel"
8
- = current_view_name
9
- i.fa-solid.fa-sort.mensa-table__views__trigger-icon
10
-
11
- .mensa-table__views__dropdown.hidden data-mensa-views-target="dropdown"
12
- ul role="listbox"
13
- - table.all_views.each do |view|
14
- - is_selected = view.id == table.table_view&.id || (view.id == :default && table.table_view.blank?)
15
- - is_user_view = view.id.is_a?(String) && view.id.match?(/\A[0-9a-f-]{32,}\z/i)
16
- li.mensa-table__views__option[role="option" data-view-id=view.id data-view-name=view.name data-mensa-views-target="view"]
17
- button.mensa-table__views__option-btn[type="button" data-action="mensa-views#select" data-view-id=view.id]
18
- i.mensa-table__views__option-check.fa-solid.fa-check class=("invisible" unless is_selected)
19
- span = view.name
20
- - if is_user_view
21
- button.mensa-table__views__option-menu[type="button" data-action="mensa-views#toggleSubmenu" data-view-id=view.id title="View options"]
22
- i.fa-solid.fa-ellipsis
23
- - else
24
- .mensa-table__views__option-system
25
- i.fa-solid.fa-ban
26
-
27
- / Per-view submenu (shown via JS positioning)
28
- .mensa-table__views__submenu.hidden data-mensa-views-target="submenu"
29
- button.mensa-table__views__submenu-item[type="button" data-action="mensa-views#renameView"]
30
- i.fa-solid.fa-pencil
31
- = t(".rename_view", default: "Rename view")
32
- button.mensa-table__views__submenu-item[type="button" data-action="mensa-views#duplicateView"]
33
- i.fa-solid.fa-copy
34
- = t(".duplicate_view", default: "Duplicate view")
35
- button.mensa-table__views__submenu-item.mensa-table__views__submenu-item--danger[type="button" data-action="mensa-views#deleteView"]
36
- i.fa-solid.fa-trash
37
- = t(".delete_view", default: "Delete view")
38
-
39
- / Rename dialog
40
- dialog.mensa-table__views__rename-dialog data-mensa-views-target="renameDialog" data-action="click->mensa-views#renameDialogBackdrop"
41
- form.mensa-table__views__rename-form data-action="submit->mensa-views#confirmRename"
42
- input type="hidden" data-mensa-views-target="renameViewId"
43
- h3.mensa-table__views__rename-title
44
- = t(".rename_view", default: "Rename view")
45
- label.mensa-table__views__rename-label
46
- = t(".view_name", default: "Name")
47
- input.mensa-table__views__rename-input[type="text" required=true placeholder=t(".view_name_placeholder", default: "View name") data-mensa-views-target="renameInput"]
48
- .mensa-table__views__rename-actions
49
- button.mensa-table__views__rename-btn.mensa-table__views__rename-btn--secondary[type="button" data-action="mensa-views#cancelRename"]
50
- = t(".cancel", default: "Cancel")
51
- button.mensa-table__views__rename-btn.mensa-table__views__rename-btn--primary[type="submit"]
52
- = t(".rename", default: "Rename")
@@ -1,5 +0,0 @@
1
- / Download counter shown on the export button. Hidden while there are no
2
- / completed downloads. Replaced via Turbo stream when a job finishes.
3
- - count = Mensa::Export.completed_count(table_name, user)
4
- span id=Mensa::Export.badge_dom_id(table_name, user) class="mensa-table__control_bar__badge #{'hidden' unless count.positive?}" aria-hidden=(count.positive? ? "false" : "true")
5
- = count
@@ -1,42 +0,0 @@
1
- / Export dialog rendered once per table inside the control bar. Opening it
2
- / refreshes the downloads list; submitting the form creates a new export.
3
- - user = table.current_user
4
- - exports = Mensa::Export.for_table(table.name).for_user(user).recent
5
- dialog.mensa-table__export-dialog data-mensa-table-target="exportDialog" data-action="click->mensa-table#exportDialogBackdrop"
6
- .mensa-table__export-dialog__panel
7
- header.mensa-table__export-dialog__header
8
- h2.mensa-table__export-dialog__title
9
- = t("mensa.exports.title", default: "Export %{table}", table: table.name.to_s.humanize)
10
- button.mensa-table__export-dialog__close type="button" data-action="mensa-table#cancelExport" aria-label=t("mensa.exports.close", default: "Close")
11
- i.fa-solid.fa-xmark
12
-
13
- .mensa-table__export-dialog__body
14
- = render partial: "mensa/exports/list", locals: {table_name: table.name, user: user, exports: exports}
15
-
16
- form.mensa-table__export-dialog__form data-action="submit->mensa-table#confirmExport"
17
- fieldset.mensa-table__export-dialog__fieldset
18
- legend.mensa-table__export-dialog__section-title
19
- = t("mensa.exports.new_export", default: "New export")
20
- label.mensa-table__export-dialog__option
21
- input type="radio" name="scope" value="all" checked=true
22
- span = t("mensa.exports.scope_all", default: "All records (matching current filters)")
23
- label.mensa-table__export-dialog__option
24
- input type="radio" name="scope" value="current_page"
25
- span = t("mensa.exports.scope_current_page", default: "Current page")
26
-
27
- fieldset.mensa-table__export-dialog__fieldset
28
- legend.mensa-table__export-dialog__section-title
29
- = t("mensa.exports.export_as", default: "Export as")
30
- label.mensa-table__export-dialog__option
31
- input type="radio" name="export_format" value="csv_excel" checked=true
32
- span = t("mensa.exports.format_excel", default: "CSV for Excel, Numbers, or other spreadsheet programs")
33
- label.mensa-table__export-dialog__option
34
- input type="radio" name="export_format" value="plain_csv"
35
- span = t("mensa.exports.format_plain", default: "Plain CSV file")
36
-
37
- .mensa-table__export-dialog__actions
38
- button.mensa-table__export-dialog__button.mensa-table__export-dialog__button--secondary type="button" data-action="mensa-table#cancelExport"
39
- = t("mensa.exports.cancel", default: "Cancel")
40
- button.mensa-table__export-dialog__button.mensa-table__export-dialog__button--primary type="submit"
41
- i.fa-solid.fa-file-export
42
- = t("mensa.exports.submit", default: "Export")
@@ -1,29 +0,0 @@
1
- / The list of a user's downloads for a table. Replaced via Turbo stream when a
2
- / new export is created or finishes processing.
3
- div id=Mensa::Export.list_dom_id(table_name, user) class="mensa-table__export-dialog__downloads"
4
- h3.mensa-table__export-dialog__section-title
5
- = t("mensa.exports.available_downloads", default: "Available downloads")
6
- - if exports.blank?
7
- p.mensa-table__export-dialog__empty
8
- = t("mensa.exports.empty", default: "You have no downloads yet. Create one below.")
9
- - else
10
- ul.mensa-table__export-dialog__list
11
- - exports.each do |export|
12
- li.mensa-table__export-dialog__item
13
- .mensa-table__export-dialog__item-info
14
- span.mensa-table__export-dialog__item-name
15
- = export.filename.presence || t("mensa.exports.item_name", default: "%{table} export", table: export.table_name.to_s.humanize)
16
- span.mensa-table__export-dialog__item-meta
17
- = export.created_at.strftime("%Y-%m-%d %H:%M")
18
- .mensa-table__export-dialog__item-action
19
- - if export.downloadable?
20
- = link_to mensa.download_table_export_path(export.table_name, export), class: "mensa-table__export-dialog__download", data: {turbo: false} do
21
- i.fa-solid.fa-download
22
- = t("mensa.exports.download", default: "Download")
23
- - elsif export.failed?
24
- span.mensa-table__export-dialog__status.mensa-table__export-dialog__status--failed
25
- = t("mensa.exports.failed", default: "Failed")
26
- - else
27
- span.mensa-table__export-dialog__status.mensa-table__export-dialog__status--pending
28
- i.fa-solid.fa-spinner.fa-spin
29
- = t("mensa.exports.processing", default: "Preparing…")
@@ -1,36 +0,0 @@
1
- = turbo_stream.update params[:target] do
2
- .mensa-table__add_filter__popover_container__heading
3
- = @column.human_name
4
- - if @column.filter.operator_with_value?
5
- - collection = @column.filter.collection
6
- - if collection.present?
7
- - unless @multiple
8
- input[type="hidden" data-mensa-add-filter-target="value" value=@values.first]
9
- ul.mensa-table__add_filter__popover_container__values data-multiple=("true" if @multiple)
10
- - collection.each do |item|
11
- - opt_label = item.is_a?(Array) ? item.first.to_s : item.to_s
12
- - opt_value = item.is_a?(Array) ? item.last.to_s : item.to_s
13
- - is_selected = @values.include?(opt_value)
14
- li.mensa-table__add_filter__popover_container__value[data-mensa-add-filter-target="valueOption" data-value=opt_value data-label=opt_label data-selected=("true" if is_selected) data-action="click->mensa-add-filter#selectValue mouseenter->mensa-add-filter#highlightItem"]
15
- - if @multiple
16
- span.mensa-table__add_filter__checkbox class=("mensa-table__add_filter__checkbox--checked" if is_selected)
17
- - else
18
- i.mensa-table__add_filter__popover_container__value__check.fa-solid.fa-check class=("invisible" unless is_selected)
19
- span.flex-1
20
- = opt_label
21
- span.mensa-table__add_filter__enter-hint
22
- | ↵ Enter
23
- - else
24
- input.mensa-table__add_filter__popover_container__input[type=@column.filter.input_type value=@values.first autocomplete="off" inputmode=(@column.type == :integer ? "numeric" : nil) step=(@column.type == :integer ? 1 : (@column.type == :datetime ? 1 : nil)) data-mensa-add-filter-target="value" data-action="input->mensa-add-filter#manualValueChanged keydown.enter->mensa-add-filter#applyManualValue"]
25
- hr.mensa-table__add_filter__popover_container__separator
26
- ul.mensa-table__add_filter__popover_container__operators
27
- - @column.filter.operators.each do |operator_name, label, requires_value|
28
- li.mensa-table__add_filter__popover_container__operator[data-mensa-add-filter-target="operatorOption" data-operator=operator_name data-requires-value=(requires_value ? "true" : "false") data-selected=("true" if @operator == operator_name.to_s) data-action="click->mensa-add-filter#selectOperator mouseenter->mensa-add-filter#highlightItem"]
29
- i.mensa-table__add_filter__popover_container__operator__check.fa-solid.fa-check class=("invisible" unless @operator == operator_name.to_s)
30
- span.flex-1
31
- = label
32
- span.mensa-table__add_filter__enter-hint
33
- | ↵ Enter
34
- hr.mensa-table__add_filter__popover_container__separator
35
- a.mensa-table__add_filter__popover_container__clear[href="#" data-action="click->mensa-add-filter#reset"]
36
- | Clear
@@ -1,4 +0,0 @@
1
- | Test
2
- button.text-xs Esc
3
- turbo-frame id=@table.table_id target="_top"
4
- = render Mensa::View::Component.new(@table)
@@ -1,5 +0,0 @@
1
- = turbo_stream.update "filters-#{@table.table_id}" do
2
- = render Mensa::FilterPillList::Component.new(table: @table)
3
-
4
- = turbo_stream.update @table.table_id do
5
- = render Mensa::View::Component.new(@table)
@@ -1,11 +0,0 @@
1
- / Replace the views tabs so the newly saved view tab appears, selected.
2
- = turbo_stream.replace "mensa-views-#{@table.table_id}" do
3
- = render Mensa::Views::Component.new(table: @table)
4
-
5
- / Clear the filter pills — the saved view starts fresh with no extra filters.
6
- = turbo_stream.update "filters-#{@table.table_id}" do
7
- = render Mensa::FilterPillList::Component.new(table: @table)
8
-
9
- / Re-render the table body with the saved view's data.
10
- = turbo_stream.update @table.table_id do
11
- = render Mensa::View::Component.new(@table)
@@ -1,11 +0,0 @@
1
- / Replace the views dropdown without the deleted view; @table is at the default view.
2
- = turbo_stream.replace "mensa-views-#{@table.table_id}" do
3
- = render Mensa::Views::Component.new(table: @table)
4
-
5
- / Reset the search bar to the default view state.
6
- = turbo_stream.update "filters-#{@table.table_id}" do
7
- = render Mensa::FilterPillList::Component.new(table: @table)
8
-
9
- / Re-render the table body with the default view data.
10
- = turbo_stream.update @table.table_id do
11
- = render Mensa::View::Component.new(@table)
@@ -1,11 +0,0 @@
1
- / Replace the views tabs so the updated view tab stays selected.
2
- = turbo_stream.replace "mensa-views-#{@table.table_id}" do
3
- = render Mensa::Views::Component.new(table: @table)
4
-
5
- / Clear the filter pills — the view now reflects the saved config.
6
- = turbo_stream.update "filters-#{@table.table_id}" do
7
- = render Mensa::FilterPillList::Component.new(table: @table)
8
-
9
- / Re-render the table body with the updated view's data.
10
- = turbo_stream.update @table.table_id do
11
- = render Mensa::View::Component.new(@table)