mensa 0.1.0 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/gem-push.yml +11 -0
  3. data/.gitignore +12 -0
  4. data/Gemfile +10 -8
  5. data/Gemfile.lock +299 -0
  6. data/MIT-LICENSE +20 -0
  7. data/Procfile +2 -0
  8. data/README.md +76 -18
  9. data/Rakefile +5 -13
  10. data/app/assets/config/mensa_manifest.js +5 -0
  11. data/app/assets/images/mensa/.keep +0 -0
  12. data/app/assets/stylesheets/mensa/application.css +11 -0
  13. data/app/components/mensa/add_filter/component.css +13 -0
  14. data/app/components/mensa/add_filter/component.html.slim +16 -0
  15. data/app/components/mensa/add_filter/component.rb +13 -0
  16. data/app/components/mensa/add_filter/component_controller.js +84 -0
  17. data/app/components/mensa/application_component.rb +12 -0
  18. data/app/components/mensa/cell/component.css +0 -0
  19. data/app/components/mensa/cell/component.html.slim +1 -0
  20. data/app/components/mensa/cell/component.rb +15 -0
  21. data/app/components/mensa/control_bar/component.css +5 -0
  22. data/app/components/mensa/control_bar/component.html.slim +15 -0
  23. data/app/components/mensa/control_bar/component.rb +21 -0
  24. data/app/components/mensa/filters/component.css +14 -0
  25. data/app/components/mensa/filters/component.html.slim +14 -0
  26. data/app/components/mensa/filters/component.rb +13 -0
  27. data/app/components/mensa/filters/component_controller.js +14 -0
  28. data/app/components/mensa/header/component.css +54 -0
  29. data/app/components/mensa/header/component.html.slim +8 -0
  30. data/app/components/mensa/header/component.rb +19 -0
  31. data/app/components/mensa/row_action/component.css +0 -0
  32. data/app/components/mensa/row_action/component.html.slim +6 -0
  33. data/app/components/mensa/row_action/component.rb +19 -0
  34. data/app/components/mensa/search/component.css +13 -0
  35. data/app/components/mensa/search/component.html.slim +17 -0
  36. data/app/components/mensa/search/component.rb +13 -0
  37. data/app/components/mensa/search/component_controller.js +62 -0
  38. data/app/components/mensa/table/component.css +0 -0
  39. data/app/components/mensa/table/component.html.slim +7 -0
  40. data/app/components/mensa/table/component.rb +16 -0
  41. data/app/components/mensa/table/component_controller.js +72 -0
  42. data/app/components/mensa/table_row/component.css +0 -0
  43. data/app/components/mensa/table_row/component.html.slim +6 -0
  44. data/app/components/mensa/table_row/component.rb +19 -0
  45. data/app/components/mensa/view/component.css +78 -0
  46. data/app/components/mensa/view/component.html.slim +17 -0
  47. data/app/components/mensa/view/component.rb +16 -0
  48. data/app/components/mensa/views/component.css +13 -0
  49. data/app/components/mensa/views/component.html.slim +18 -0
  50. data/app/components/mensa/views/component.rb +14 -0
  51. data/app/controllers/concerns/.keep +0 -0
  52. data/app/controllers/mensa/application_controller.rb +4 -0
  53. data/app/controllers/mensa/tables/filters_controller.rb +29 -0
  54. data/app/controllers/mensa/tables_controller.rb +37 -0
  55. data/app/helpers/mensa/application_helper.rb +5 -0
  56. data/app/helpers/mensa/tables_helper.rb +5 -0
  57. data/app/javascript/mensa/application.js +3 -0
  58. data/app/javascript/mensa/controllers/alert_controller.js +7 -0
  59. data/app/javascript/mensa/controllers/application.js +8 -0
  60. data/app/javascript/mensa/controllers/application_controller.js +57 -0
  61. data/app/javascript/mensa/controllers/index.js +24 -0
  62. data/app/jobs/mensa/application_job.rb +7 -0
  63. data/app/jobs/mensa/export_job.rb +91 -0
  64. data/app/models/concerns/.keep +0 -0
  65. data/app/models/mensa/application_record.rb +5 -0
  66. data/app/models/mensa/table_view.rb +5 -0
  67. data/app/tables/mensa/action.rb +26 -0
  68. data/app/tables/mensa/base.rb +103 -0
  69. data/app/tables/mensa/cell.rb +50 -0
  70. data/app/tables/mensa/column.rb +85 -0
  71. data/app/tables/mensa/config/action_dsl.rb +12 -0
  72. data/app/tables/mensa/config/column_dsl.rb +23 -0
  73. data/app/tables/mensa/config/dsl_logic.rb +90 -0
  74. data/app/tables/mensa/config/filter_dsl.rb +8 -0
  75. data/app/tables/mensa/config/render_dsl.rb +8 -0
  76. data/app/tables/mensa/config/table_dsl.rb +71 -0
  77. data/app/tables/mensa/config_readers.rb +13 -0
  78. data/app/tables/mensa/filter.rb +31 -0
  79. data/app/tables/mensa/row.rb +36 -0
  80. data/app/tables/mensa/scope.rb +99 -0
  81. data/app/views/layouts/mensa/application.html.slim +11 -0
  82. data/app/views/mensa/tables/filters/show.turbo_stream.slim +8 -0
  83. data/app/views/mensa/tables/index.html.slim +93 -0
  84. data/app/views/mensa/tables/show.html.slim +5 -0
  85. data/app/views/mensa/tables/show.turbo_stream.slim +5 -0
  86. data/bin/importmap +4 -0
  87. data/bin/rails +14 -0
  88. data/config/importmap.rb +8 -0
  89. data/config/locales/en.yml +8 -0
  90. data/config/locales/nl.yml +11 -0
  91. data/config/routes.rb +7 -0
  92. data/db/migrate/20240201184752_create_mensa_table_views.rb +15 -0
  93. data/lib/generators/mensa/install_generator.rb +24 -0
  94. data/lib/generators/mensa/tailwind_config_generator.rb +24 -0
  95. data/lib/generators/mensa/templates/config/initializers/mensa.rb +22 -0
  96. data/lib/mensa/configuration.rb +90 -0
  97. data/lib/mensa/engine.rb +37 -0
  98. data/lib/mensa/version.rb +1 -3
  99. data/lib/mensa.rb +24 -5
  100. data/lib/tasks/mensa_tasks.rake +13 -0
  101. data/mensa.gemspec +42 -0
  102. data/package.json +10 -0
  103. data/vendor/javascript/@rails--request.js.js +2 -0
  104. data/yarn.lock +837 -0
  105. metadata +245 -18
  106. data/.rubocop.yml +0 -13
  107. data/CHANGELOG.md +0 -5
  108. data/CODE_OF_CONDUCT.md +0 -84
  109. data/LICENSE.txt +0 -21
  110. data/sig/mensa.rbs +0 -4
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mensa
4
+ class ApplicationComponent < ViewComponent::Base
5
+ include ViewComponent::Slotable
6
+ include ActionView::Helpers::TranslationHelper
7
+ include Satis::Concerns::ContextualTranslations
8
+ include Mensa::ApplicationHelper
9
+
10
+ attr_accessor :original_view_context
11
+ end
12
+ end
File without changes
@@ -0,0 +1 @@
1
+ td = cell.render(:html)
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mensa
4
+ class Cell
5
+ class Component < ::Mensa::ApplicationComponent
6
+ with_collection_parameter :column
7
+
8
+ attr_reader :cell
9
+
10
+ def initialize(row:, column:)
11
+ @cell = ::Mensa::Cell.new(row: row, column: column)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ .mensa-table {
2
+ &__control_bar {
3
+ @apply pl-2 pt-1.5 pr-2;
4
+ }
5
+ }
@@ -0,0 +1,15 @@
1
+ .mensa-table__control_bar data-mensa-table-target="controlBar"
2
+ .flex.space-x-2.justify-right
3
+ button.flex.justify-right.cursor-pointer.py-1.5.h-full.text-gray-400 class="#{table.supports_views? ? 'w-8' : 'w-4'}" data-action="mensa-table#openFiltersAndSearch"
4
+ - if table.supports_views?
5
+ i class=Mensa.config.icons[:control_bar_search]
6
+ i class=Mensa.config.icons[:control_bar_filter]
7
+ /- if view_columns_sorting?
8
+ button.cursor-pointer.w-6.h-full.text-gray-400
9
+ i class=Mensa.config.icons[:control_bar_edit]
10
+ - if view_condensed_toggle?
11
+ button.cursor-pointer.w-6.h-full.text-gray-400 data-action="mensa-table#condenseExpand"
12
+ i data-mensa-table-target="condenseExpandIcon" class=Mensa.config.icons[:control_bar_compress]
13
+ - if table.config[:render]&.key?(:xlsx)
14
+ button.cursor-pointer.w-6.h-full.text-gray-400 data-action="mensa-table#export"
15
+ i data-mensa-table-target="exportIcon" class=Mensa.config.icons[:control_bar_export]
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mensa
4
+ module ControlBar
5
+ class Component < ::Mensa::ApplicationComponent
6
+ attr_reader :table
7
+
8
+ def initialize(table:)
9
+ @table = table
10
+ end
11
+
12
+ def view_columns_sorting?
13
+ table.view_columns_sorting?
14
+ end
15
+
16
+ def view_condensed_toggle?
17
+ table.view_condensed_toggle?
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ .mensa-table {
2
+ &__filters {
3
+ @apply p-2 shadow-lg border-b dark:bg-gray-700 dark:border-gray-600;
4
+
5
+ a.filter {
6
+ @apply bg-gray-200 dark:bg-gray-500 hover:bg-gray-400 text-gray-800 rounded-md px-3 py-1.5 text-sm;
7
+ }
8
+
9
+ a.filter.selected {
10
+ @apply bg-gray-100 text-gray-600 dark:text-gray-400 hover:text-gray-800 hover:bg-gray-200;
11
+ }
12
+
13
+ }
14
+ }
@@ -0,0 +1,14 @@
1
+ .mensa-table__filters.hidden data-mensa-table-target="filters"
2
+ .block
3
+ nav
4
+ .flex.space-x-2.overflow-none.whitespace-nowrap.scroll-p-0[aria-label="Tabs"]
5
+ / existing filters first
6
+ - table.active_filters.each do |filter|
7
+ .relative
8
+ button.relative.w-full.cursor-default.rounded-md.bg-white.dark:bg-gray-800.py-1.5.pl-3.text-left.text-gray-900.dark:text-gray-400.shadow-sm.ring-1.ring-inset.ring-gray-300.dark:ring-gray-600.focus:outline-none.focus:ring-2.focus:ring-primary-600.sm:text-sm.sm:leading-6[type="button" aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label"]
9
+ span.block.truncate.pr-6
10
+ = filter
11
+ span.pointer-events-none.absolute.inset-y-0.right-0.flex.items-center.pr-2
12
+ .fal.fa-angle-down
13
+
14
+ = render Mensa::AddFilter::Component.new(table: table)
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mensa
4
+ module Filters
5
+ class Component < ::Mensa::ApplicationComponent
6
+ attr_reader :table
7
+
8
+ def initialize(table:)
9
+ @table = table
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ import ApplicationController from 'mensa/controllers/application_controller'
2
+
3
+ export default class FiltersComponentController extends ApplicationController {
4
+ static targets = [
5
+ 'list',
6
+ ]
7
+ static values = {
8
+ supportsViews: Boolean
9
+ }
10
+
11
+ connect () {
12
+ super.connect()
13
+ }
14
+ }
@@ -0,0 +1,54 @@
1
+ .mensa-table {
2
+ thead {
3
+ tr {
4
+ @apply divide-x divide-gray-200 dark:divide-gray-600
5
+ }
6
+
7
+ th {
8
+ @apply top-0 z-10 py-3.5 pl-6 pr-6 px-6 align-bottom text-left text-xs font-medium text-gray-500 uppercase border-b border-gray-200 dark:border-gray-600;
9
+
10
+ .container {
11
+ @apply h-4 flex items-center;
12
+ }
13
+
14
+ .title {
15
+ @apply w-full pr-3;
16
+ }
17
+
18
+ .actions {
19
+ @apply pr-3 flex items-center;
20
+
21
+ .action {
22
+ @apply cursor-pointer;
23
+ /*.fa-arrow-down-arrow-up {*/
24
+ @apply opacity-0;
25
+ /*}*/
26
+ }
27
+ }
28
+ }
29
+
30
+ th:hover {
31
+ .actions {
32
+ .action {
33
+ /*.fa-arrow-down-arrow-up {*/
34
+ @apply opacity-100;
35
+ /*}*/
36
+ }
37
+ }
38
+ }
39
+ }
40
+ &__condensed {
41
+ thead {
42
+ th {
43
+ @apply whitespace-nowrap py-2 pl-4 pr-3 px-0;
44
+ }
45
+ }
46
+ }
47
+ &__column_edit {
48
+ thead {
49
+ th {
50
+ @apply cursor-grab;
51
+ }
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,8 @@
1
+ th
2
+ .container
3
+ .title = column.human_name
4
+ .actions
5
+ - if column.sortable?
6
+ .action
7
+ = link_to table.path(order: {column.name => column.next_sort_direction}, turbo_frame_id: table.table_id), "data-turbo-frame": "_self"
8
+ i class=Mensa.config.icons["order_indicator#{column.sort_direction.to_s.present? ? "_#{column.sort_direction.to_s}" : ""}".to_sym]
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mensa
4
+ module Header
5
+ class Component < ::Mensa::ApplicationComponent
6
+ with_collection_parameter :column
7
+
8
+ include TablesHelper
9
+
10
+ attr_reader :table
11
+ attr_reader :column
12
+
13
+ def initialize(table:, column:)
14
+ @table = table
15
+ @column = column
16
+ end
17
+ end
18
+ end
19
+ end
File without changes
@@ -0,0 +1,6 @@
1
+ - if action.show.call(row.record)
2
+ a href=(action.link ? table.original_view_context.instance_exec(row.record, &action.link) : '') title=action.name *action.link_attributes
3
+ - if action.icon
4
+ i.fa class=action.icon
5
+ - else
6
+ = name
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mensa
4
+ module RowAction
5
+ class Component < ::Mensa::ApplicationComponent
6
+ with_collection_parameter :action
7
+
8
+ attr_reader :table
9
+ attr_reader :row
10
+ attr_reader :action
11
+
12
+ def initialize(table:, row:, action:)
13
+ @table = table
14
+ @row = row
15
+ @action = action
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ .mensa-table {
2
+ &__search {
3
+ @apply dark:bg-gray-800 dark:border-gray-800 border-b p-2;
4
+
5
+ &__button {
6
+ @apply cursor-pointer w-6 h-full text-gray-400;
7
+ }
8
+
9
+ input&__input {
10
+ @apply pl-2 h-6 w-full border-0 bg-transparent pr-4 text-gray-600 dark:text-gray-400 placeholder:text-gray-400 focus:ring-0 text-sm;
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,17 @@
1
+ .mensa-table__search data-mensa-table-target="search" data-controller="mensa-search" data-mensa-search-target="search" class="#{table.supports_views? ? 'hidden' : ''}" data-mensa-search-mensa-table-outlet=".mensa-table#table-#{table.table_id}"
2
+ .flex
3
+ .flex-none.w-6.h-22.text-right.text-gray-500.dark:text-gray-400
4
+ i.cursor-pointer class=Mensa.config.icons[:search]
5
+ .flex-1
6
+ input.mensa-table__search__input type="text" name="search_query" placeholder=t("search", default: "Search") data-mensa-search-target="searchInput" data-action="mensa-search#monitorSearch keydown.enter->mensa-search#search keydown.esc->mensa-search#resetSearch" value=params[:query]
7
+ .flex.space-x-2.justify-right.pr-2
8
+ button.mensa-table__search__button.hidden.pr-6 data-mensa-search-target="resetSearchButton" data-action="mensa-search#resetSearch"
9
+ i.fas.fa-xmark
10
+ .view-buttons.space-x-2.hidden data-mensa-table-target="viewButtons"
11
+ button class="rounded bg-white px-2 py-1 text-xs font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50" data-action="mensa-table#cancelFiltersAndSearch"
12
+ = t('.cancel')
13
+ button class="rounded bg-white px-2 py-1 text-xs font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50" data-action="mensa-table#saveFiltersAndSearch"
14
+ = t('.save')
15
+ - unless table.supports_views?
16
+ = render Mensa::ControlBar::Component.new(table: table)
17
+
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mensa
4
+ module Search
5
+ class Component < ::Mensa::ApplicationComponent
6
+ attr_reader :table
7
+
8
+ def initialize(table:)
9
+ @table = table
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,62 @@
1
+ import ApplicationController from 'mensa/controllers/application_controller'
2
+
3
+ import { get } from '@rails/request.js'
4
+
5
+ export default class SearchComponentController extends ApplicationController {
6
+ static targets = [
7
+ 'resetSearchButton',
8
+ 'searchInput'
9
+ ]
10
+ static outlets = [
11
+ "mensa-table"
12
+ ]
13
+ connect () {
14
+ super.connect()
15
+ this.monitorSearch()
16
+ }
17
+
18
+ monitorSearch (event) {
19
+ if (this.searchInputTarget.value.length >= 1) {
20
+ this.resetSearchButtonTarget.classList.remove('hidden')
21
+ this.searchInputTarget.focus();
22
+ } else {
23
+ this.resetSearchButtonTarget.classList.add('hidden')
24
+ }
25
+ }
26
+
27
+ resetSearch (event) {
28
+ this.searchInputTarget.value = ''
29
+ this.searchInputTarget.focus()
30
+ this.resetSearchButtonTarget.classList.add('hidden')
31
+
32
+ let turboFrame = this.element.closest('turbo-frame')
33
+ let url = this.ourUrl
34
+ url.searchParams.delete('query')
35
+
36
+ get(url, {
37
+ responseKind: 'turbo-stream'
38
+ })
39
+ }
40
+
41
+ search (event) {
42
+ if (this.query.length < 3) {
43
+ return
44
+ }
45
+
46
+ // FIXME: This doesn't prevent searching twice on enter, the turbo-frame URL doesn't change
47
+ let url = this.ourUrl
48
+ if(url.searchParams.get('query') === this.query) {
49
+ return
50
+ }
51
+
52
+ url.searchParams.append('query', this.query)
53
+
54
+ get(url, {
55
+ responseKind: 'turbo-stream'
56
+ })
57
+ }
58
+
59
+ get query() {
60
+ return this.searchInputTarget.value
61
+ }
62
+ }
File without changes
@@ -0,0 +1,7 @@
1
+ .mensa-table id="table-#{table.table_id}" data-mensa-table-view-condensed-value="#{table.view_condensed?}" data-mensa-table-supports-views-value="#{table.supports_views?}" data-controller="mensa-table"
2
+ = render Mensa::Search::Component.new(table: table)
3
+ div id="filters-#{table.table_id}"
4
+ = render Mensa::Filters::Component.new(table: table)
5
+ - if table.supports_views? && table.show_header?
6
+ = render Mensa::Views::Component.new(table: table)
7
+ turbo-frame id=table.table_id src=helpers.mensa.table_path(table.name, turbo_frame_id: table.table_id) target="_top" loading="lazy" data-mensa-table-target="turboFrame"
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mensa
4
+ module Table
5
+ class Component < ::Mensa::ApplicationComponent
6
+ include TablesHelper
7
+
8
+ attr_reader :table
9
+
10
+ def initialize(table_name, config = {}, **options)
11
+ @table = Mensa.for_name(table_name, config)
12
+ @table.component = self
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,72 @@
1
+ import ApplicationController from 'mensa/controllers/application_controller'
2
+ import { get } from '@rails/request.js'
3
+
4
+ export default class TableComponentController extends ApplicationController {
5
+ static targets = [
6
+ 'controlBar', // Bar with buttons
7
+ 'condenseExpandIcon', // Icon
8
+ 'filters', // Tabs or list of filters
9
+ 'views', // Tabs or list of views
10
+ 'viewButtons', // Cancel and save buttons for views
11
+ 'search', // Search bar
12
+ 'view', // View contains table element
13
+ 'turboFrame' // The turbo-frame
14
+ ]
15
+ static values = {
16
+ supportsViews: Boolean
17
+ }
18
+
19
+ connect () {
20
+ super.connect()
21
+ }
22
+
23
+ openFiltersAndSearch(event) {
24
+ if(this.supportsViewsValue) {
25
+ this.viewButtonsTarget.classList.remove('hidden')
26
+ this.searchTarget.classList.remove('hidden')
27
+ this.viewsTarget.classList.add('hidden')
28
+ this.filtersTarget.classList.remove('hidden')
29
+ } else {
30
+ this.controlBarTarget.classList.add('hidden')
31
+ this.viewButtonsTarget.classList.remove('hidden')
32
+ this.filtersTarget.classList.remove('hidden')
33
+ }
34
+ }
35
+
36
+ cancelFiltersAndSearch(event) {
37
+ if(this.supportsViewsValue) {
38
+ this.searchTarget.classList.add('hidden')
39
+ this.viewButtonsTarget.classList.add('hidden')
40
+ this.filtersTarget.classList.add('hidden')
41
+ this.viewsTarget.classList.remove('hidden')
42
+ } else {
43
+ this.controlBarTarget.classList.remove('hidden')
44
+ this.viewButtonsTarget.classList.add('hidden')
45
+ this.filtersTarget.classList.add('hidden')
46
+ }
47
+ }
48
+
49
+ saveFiltersAndSearch(event) {
50
+
51
+ }
52
+
53
+ condenseExpand (event) {
54
+ if (this.viewTarget.classList.contains('mensa-table__condensed')) {
55
+ this.viewTarget.classList.remove('mensa-table__condensed')
56
+ this.condenseExpandIconTarget.classList.add('fa-compress')
57
+ this.condenseExpandIconTarget.classList.remove('fa-expand')
58
+ } else {
59
+ this.viewTarget.classList.add('mensa-table__condensed')
60
+ this.condenseExpandIconTarget.classList.remove('fa-compress')
61
+ this.condenseExpandIconTarget.classList.add('fa-expand')
62
+ }
63
+ }
64
+
65
+ export(event) {
66
+ let url = this.ourUrl
67
+ url.pathname += ".xlsx"
68
+ get(url, {
69
+ }).then(() => {
70
+ })
71
+ }
72
+ }
File without changes
@@ -0,0 +1,6 @@
1
+ tr *row.link_attributes
2
+ = render(Mensa::Cell::Component.with_collection(table.display_columns, row: row))
3
+ - if table.actions?
4
+ td.flex.space-x-2
5
+ = render(Mensa::RowAction::Component.with_collection(table.actions, row: row, table: table))
6
+ | &nbsp;
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mensa
4
+ module TableRow
5
+ class Component < ::Mensa::ApplicationComponent
6
+ with_collection_parameter :row
7
+
8
+ include TablesHelper
9
+
10
+ attr_reader :table
11
+ attr_reader :row
12
+
13
+ def initialize(table:, row:)
14
+ @table = table
15
+ @row = row
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,78 @@
1
+ .mensa-table {
2
+ @apply bg-white dark:bg-gray-500 dark:border-gray-700;
3
+
4
+ .badge {
5
+ @apply bg-primary-100 text-primary-600 hidden ml-3 rounded-full text-xs font-medium md:inline-block py-0.5 px-2.5;
6
+ }
7
+
8
+ table {
9
+ @apply min-w-full divide-y divide-gray-50 dark:divide-gray-800 border-0;
10
+
11
+ thead {
12
+ @apply bg-gray-100 top-0 dark:bg-gray-700 dark:font-medium dark:text-gray-400 dark:lowercase;
13
+
14
+ /* tr and th moved to header */
15
+ }
16
+
17
+ tbody {
18
+
19
+ @apply divide-y divide-gray-200 dark:divide-gray-600;
20
+
21
+ tr {
22
+ @apply cursor-pointer bg-white dark:bg-gray-800 divide-x divide-gray-400 divide-opacity-25 hover:bg-gray-100 dark:hover:bg-gray-700;
23
+
24
+ &:nth-child(even) {
25
+ @apply bg-gray-50 dark:bg-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700;
26
+ }
27
+ }
28
+
29
+ td {
30
+ @apply px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400;
31
+ }
32
+ }
33
+ }
34
+
35
+ .paging {
36
+ @apply flex items-center justify-between border-t border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-800 px-4 py-3 sm:px-6;
37
+
38
+
39
+ .pagy {
40
+ @apply flex space-x-1 text-sm text-gray-500;
41
+
42
+ a:not(.gap) {
43
+ @apply block rounded-lg px-3 py-1 bg-gray-200 no-underline;
44
+
45
+ &:hover {
46
+ @apply bg-gray-300;
47
+ }
48
+
49
+ &:not([href]) {
50
+ /* disabled links */
51
+ @apply text-gray-300 bg-gray-100 cursor-default;
52
+ }
53
+
54
+ &.current {
55
+ @apply text-white bg-primary-600;
56
+ }
57
+ }
58
+
59
+ label {
60
+ @apply inline-block whitespace-nowrap bg-gray-200 rounded-lg px-3 py-0.5;
61
+
62
+ input {
63
+ @apply bg-gray-100 border-none rounded-md;
64
+ }
65
+ }
66
+ }
67
+
68
+ &__condensed {
69
+ table {
70
+ tbody {
71
+ td {
72
+ @apply pl-4 py-2;
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,17 @@
1
+ .overflow-y-auto class=(table.view_condensed? ? "mensa-table__condensed" : "") data-mensa-table-target="view"
2
+ table.w-full
3
+ - if table.show_header?
4
+ thead
5
+ tr
6
+ = render(Mensa::Header::Component.with_collection(table.columns.select(&:visible?).reject(&:internal?), table: table))
7
+ - if table.actions?
8
+ th
9
+
10
+ tbody
11
+ = render(Mensa::TableRow::Component.with_collection(table.rows, table: table))
12
+
13
+ - if table.pagy_details&.pages > 1 || table.pagy_details.count == 0
14
+ .paging
15
+ == pagy_info(table.pagy_details)
16
+ - if table.pagy_details&.pages > 1
17
+ == pagy_nav(table.pagy_details)
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Presents a single table-view, also in use when just one table is in view
4
+ module Mensa
5
+ module View
6
+ class Component < ::Mensa::ApplicationComponent
7
+ include TablesHelper
8
+
9
+ attr_reader :table
10
+
11
+ def initialize(table)
12
+ @table = table
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ .mensa-table {
2
+ &__views {
3
+ @apply p-2 pl-4 shadow-lg border-b dark:bg-gray-700 dark:border-gray-600;
4
+
5
+ a.view {
6
+ @apply bg-gray-100 text-gray-600 dark:text-gray-400 hover:text-gray-800 hover:bg-gray-200 rounded-md px-3 py-1.5 text-sm;
7
+ }
8
+
9
+ a.view.selected {
10
+ @apply bg-gray-300 text-gray-800 dark:bg-gray-500 hover:bg-gray-400;
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,18 @@
1
+ .mensa-table__views data-mensa-table-target="views"
2
+ .sm:hidden
3
+ label.sr-only[for="tabs"]
4
+ | Select a tab
5
+ select#tabs.block.w-full.rounded-md.border-gray-300.focus:border-indigo-500.focus:ring-indigo-500[name="tabs"]
6
+ - table.all_views.each.with_index do |view, index|
7
+ option = view.name
8
+ .hidden.sm:block
9
+ nav.flex.justify-between[aria-label="Tabs"]
10
+ .flex.space-x-2.overflow-x-auto.whitespace-nowrap.scroll-p-0
11
+ - table.all_views.each.with_index do |view, index|
12
+ = link_to(table.path(table_view_id: view.id, turbo_frame_id: table.table_id), "data-turbo-frame": table.table_id, class: "view #{(view == table.table_view) || (!view.persisted? && table.table_view.blank?) ? 'selected' : ''}") do
13
+ = view.name
14
+
15
+ a.text-gray-600.dark:text-gray-400.hover:text-gray-800.hover:bg-gray-200.rounded-md.px-3.py-1.5.text-sm[href="#" title=t("new_view", default: "New view")]
16
+ .fal.fa-plus
17
+ - if table.supports_views?
18
+ = render Mensa::ControlBar::Component.new(table: table)
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mensa
4
+ module Views
5
+ class Component < ::Mensa::ApplicationComponent
6
+ # renders_many :views
7
+ attr_reader :table
8
+
9
+ def initialize(table:)
10
+ @table = table
11
+ end
12
+ end
13
+ end
14
+ end
File without changes
@@ -0,0 +1,4 @@
1
+ module Mensa
2
+ class ApplicationController < ActionController::Base#::Mensa.config.base_controller.constantize
3
+ end
4
+ end