From 7fc2faeaf063e33f049c46676a7b9182a8d36e38 Mon Sep 17 00:00:00 2001 From: miteruzo Date: Thu, 29 Oct 2026 22:26:49 +0900 Subject: [PATCH] #434 --- backend/app/services/counts_table_query.rb | 20 ++++++++++++-------- frontend/src/App.tsx | 6 +++--- frontend/src/components/TopNav.tsx | 4 ++++ frontend/src/locales/ja/navigation.json | 2 ++ 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/backend/app/services/counts_table_query.rb b/backend/app/services/counts_table_query.rb index 40acc1e..49bb3fe 100644 --- a/backend/app/services/counts_table_query.rb +++ b/backend/app/services/counts_table_query.rb @@ -79,7 +79,7 @@ class CountsTableQuery selected = expressions.each_with_index.map do |expression, index| "#{ expression } AS a#{ index }" end - source = population.scope + source = summary_population.scope source = source.joins(axes.joins) unless axes.joins.empty? sql = if expressions.empty? source.except(:select).select('COUNT(DISTINCT v.id) AS count').to_sql @@ -165,7 +165,7 @@ class CountsTableQuery other_count: axes.rows.length, direction: :column) .map { _1.merge(kind: 'grand_total') } end - totals = CountsPivotTotals.new(population, axes, row_headers, column_headers).call + totals = CountsPivotTotals.new(summary_population, axes, row_headers, column_headers).call { group_count: total, visible_output_count: axes.rows.empty? ? 1 : total, column_values:, row_headers:, column_headers:, pivot_totals: totals, @@ -223,6 +223,10 @@ class CountsTableQuery @params.merge('execution_at' => population.at.iso8601(6)), authorisation_flg: false) end + def summary_population + unrestricted_population + end + def record_counts return @record_counts if @record_counts @@ -247,7 +251,7 @@ class CountsTableQuery @record_counts = { total: total.to_i, denied: denied.to_i, visible: } end - def output_totals(visible_rows) + def output_totals visible_rows return @output_totals if @output_totals if HistoryAccess.admin? @@ -289,7 +293,7 @@ class CountsTableQuery def locale = @locale ||= Locale.find_by!(code: @params.fetch('locale', 'ja')) - def limited_columns(prefix) + def limited_columns prefix keys = axes.columns.each_index.map { "a#{ axes.rows.length + _1 }" } return [[]] if keys.empty? @@ -315,9 +319,9 @@ class CountsTableQuery values end - def measure_relation(values) + def measure_relation values row_expressions = axes.expressions.first(axes.rows.length) - source = population.scope.except(:select, :order) + source = summary_population.scope.except(:select, :order) fields = axes.rows + axes.columns.first(values.length) joins = axes.joins(fields.map { _1.fetch('field') }) source = source.joins(joins) unless joins.empty? @@ -332,7 +336,7 @@ class CountsTableQuery source.select(Arel.sql(selected.join(', '))).to_sql end - def axis_order_sql(key, direction = 'asc', qualifier: nil) + def axis_order_sql key, direction = 'asc', qualifier: nil column = qualifier ? "#{ qualifier }.#{ key }" : key expression = column if axes.all.fetch(key.delete_prefix('a').to_i).fetch('field') == 'category' @@ -345,7 +349,7 @@ class CountsTableQuery "#{ column } IS NULL ASC, #{ expression } #{ direction.upcase }" end - def measure_values(key) + def measure_values key records = QueryState.records(@params, 'measures').select { _1['key'] == key } raise ArgumentError if records.empty? raise ArgumentError unless records.map { _1['axis'] }.sort == (0...records.length).to_a diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 3feb7d9..4f86c30 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -205,11 +205,11 @@ export const pageRoutes = ( handle: { preload: CountsResourcePage.preload, prefetch: false, robots: 'noindex' } }, { path: 'counts/tags', element: , handle: { preload: CountsResourcePage.preload, prefetch: false, robots: 'noindex' } }, - { path: 'counts/nico_tags', element: , + { path: 'counts/nico-tags', element: , handle: { preload: CountsResourcePage.preload, prefetch: false, robots: 'noindex' } }, - { path: 'counts/tag_descriptions', element: , + { path: 'counts/tag-descriptions', element: , handle: { preload: CountsResourcePage.preload, prefetch: false, robots: 'noindex' } }, - { path: 'counts/tag_groups', element: , + { path: 'counts/tag-groups', element: , handle: { preload: CountsResourcePage.preload, prefetch: false, robots: 'noindex' } }, { path: 'counts/materials', element: , handle: { preload: CountsResourcePage.preload, prefetch: false, robots: 'noindex' } }, diff --git a/frontend/src/components/TopNav.tsx b/frontend/src/components/TopNav.tsx index 4904b96..ffda722 100644 --- a/frontend/src/components/TopNav.tsx +++ b/frontend/src/components/TopNav.tsx @@ -120,6 +120,10 @@ export const menuOutline = ( { ...message ('entertainment'), visible: false, subMenu: [ { ...message ('theatre'), to: '/theatres/1' }, { ...message ('gekanator'), to: '/gekanator' }] }, + { ...message ('counts'), visible: false, subMenu: [ + { ...message ('posts'), to: '/counts/posts' }, + { ...message ('tags'), to: '/counts/tags' }, + { ...message ('externalTags'), to: '/counts/nico-tags' }] }, { ...message ('users'), to: '/users/settings', visible: false, subMenu: [ { ...message ('list'), to: '/users', visible: false }, { ...message ('currentUser'), to: `/users/${ user?.id }`, visible: false }, diff --git a/frontend/src/locales/ja/navigation.json b/frontend/src/locales/ja/navigation.json index 6f17274..5e00f5e 100644 --- a/frontend/src/locales/ja/navigation.json +++ b/frontend/src/locales/ja/navigation.json @@ -18,6 +18,8 @@ "entertainment": "おたのしみ", "theatre": "上映会 (β)", "gekanator": "グカネータ (β)", + "counts": "集計", + "externalTags": "外部タグ", "users": "ユーザ", "currentUser": "お前", "settings": "設定",