.container-fluid#reportsPage v-cloak="" data-controller="reports" .row .col-md-3 = render partial: "respondent_categories/sidebar" .col-md-9 = render_breadcrumbs([ \ { name: 'Home', path: projects_path }, \ { name: @project.title, path: project_path(@project) }, \ { name: @respondent_category.name, path: [@project, @respondent_category] }, \ { name: "Analysis Reports", path: analysis_reports_project_respondent_category_path(@project, @respondent_category) }, \ { name: "All Data Report" } \ ]) .fs-16.semi-bold.mb-4 = @respondent_category.name .d-flex.justify-content-between.align-items-center.mb-4 .d-flex.align-items-center.gap-3 .fs-24 All Data Dashboard / Dropdown to toggle reports select.form-select.w-auto.shadow-sm v-model="currentReport" @change="handleReportChange" - if @respondent_category.transcript_sections.present? option value="sections" Sections Report option value="insights" Insights Report - if @respondent_category.highlight_themes.joins(:transcript_highlights).exists? option value="themes" Themes Report / Dynamic buttons based on current report .d-flex.flex-wrap.gap-2 = link_to download_all_data_report_project_respondent_category_path(@project, @respondent_category), class: "btn btn-success fs-12", target: "_blank" do i.bi.bi-file-earmark-excel.me-2.fs-10 | Download / ----------------------------------------------------- / Action Buttons for Sections / ----------------------------------------------------- template v-if="isSectionsReport" button.transliteration-toggle.btn.fs-12[ :class="transliterationEnabled ? 'btn-primary' : 'btn-outline-primary'" @click="toggleTransliteration" ] {{ transliterationEnabled ? 'Transliteration On' : 'Transliteration Off' }} / ----------------------------------------------------- / Action Buttons for Insights / ----------------------------------------------------- template v-if="isInsightsReport" / ----------------------------------------------------- / Action Buttons for Themes / ----------------------------------------------------- template v-if="isThemesReport" / ----------------------------------------------------- / View Toggles for Sections / Insights / ----------------------------------------------------- template v-if="isSectionsReport || isInsightsReport" select.form-select.w-auto.shadow-sm.fs-12 v-model="currentView" @change="handleViewChange" option value="raw" Raw Grid option value="analysis" Summary Grid option value="aggregate" Aggregate Summary / ----------------------------------------------------- / View Toggles for Themes / ----------------------------------------------------- template v-if="isThemesReport" select.form-select.w-auto.shadow-sm.fs-12 v-model="currentView" @change="handleViewChange" option value="highlight" Sectioned Highlights option value="raw" Themed Raw Highlights option value="unthemed" Un-themed Highlights .reports-container / ========================================================================= / SECTIONS REPORT BLOCK / ========================================================================= div v-if="isSectionsReport" - if @respondent_category.transcript_sections.present? .reports-table v-show="isRawView" ref="rawTable" table.table-striped.table.table-bordered.table-responsive style="transform: translate3d(0, 0, 0);" thead.fs-12 tr th button.btn.btn-sm.btn-outline-primary.py-1.px-2.fs-12[ @click="toggleAllInTable" style="width: fit-content; min-height: 22px; line-height: 1.2" ] vue-feather.mt-1[ :type="tableExpanded ? 'minimize-2' : 'maximize-2'" size="16" ] - @respondents.each do |respondent| th.p-4 style="min-width: 300px;" = link_to respondent.name, [respondent.project, respondent.respondent_category, respondent], target: "_blank" - unless respondent.tags.empty? .d-flex.flex-wrap.gap-1.mt-1 - respondent.tags.includes(:tag_category).each do |tag| span.badge.bg-secondary.me-2.text-black.fs-10 = tag.tag_category.name |: = tag.name tbody.fs-12 - @sections.each do |section| tr td.p-4.align-top.semi-bold .sticky-row-header expandable-row[ :section-name="'#{section[0]}'" :section-id="'#{section[1]}'" :parent-expanded="tableExpanded" @toggle-row="expanded => toggleRowExpansion('#{section[1]}', expanded)" ] - @respondents.each do |r| td.align-top.p-4 - transcript_sections = r.transcript_sections.select{|x|x.master_section_id == section[1]} - if !transcript_sections.empty? - transcript_sections.each_with_index do |transcript_section, i| - if transcript_sections.count > 1 strong = "Excerpt #{i+1}" - if ["hi", "multi"].include?(r.language) expandable-text( :text="transliterate(#{transcript_section.content.to_json})" :force-expanded="getRowExpansionState('#{section[1]}')" @expansion-changed="expanded => handleCellExpansion('#{section[1]}')" ) - else expandable-text( :text="#{transcript_section.content.to_json}" :force-expanded="getRowExpansionState('#{section[1]}')" @expansion-changed="expanded => handleCellExpansion('#{section[1]}')" ) - if transcript_sections.count > 1 .mb-2 - else .text-muted.fst-italic | No Data Found .reports-table v-show="isAnalysisView" ref="analysisTable" table.table-striped.table.table-bordered.table-responsive style="transform: translate3d(0, 0, 0);" thead.fs-12 tr th button.btn.btn-sm.btn-outline-primary.py-1.px-2.fs-12[ @click="toggleAllInTable" style="width: fit-content; min-height: 22px; line-height: 1.2" ] vue-feather.mt-1[ :type="tableExpanded ? 'minimize-2' : 'maximize-2'" size="16" ] - @respondents.each do |respondent| th.p-4 style="min-width: 300px;" = link_to respondent.name, [respondent.project, respondent.respondent_category, respondent], target: "_blank" tbody.fs-12 - @sections.each do |section| tr td.p-4.align-top.semi-bold .sticky-row-header expandable-row[ :section-name="'#{section[0]}'" :section-id="'#{section[1]}'" :parent-expanded="tableExpanded" @toggle-row="expanded => toggleRowExpansion('#{section[1]}', expanded)" ] - @respondents.each do |r| td.align-top.p-4 - transcript_sections = r.transcript_sections.select{|x| x.master_section_id == section[1]} - if !transcript_sections.empty? - transcript_sections.each_with_index do |transcript_section, i| - if transcript_section and !transcript_section.ai_summary.blank? - if transcript_sections.count > 1 strong = "Excerpt #{i+1} summary" expandable-text( :text="#{transcript_section.ai_summary_markdown.to_json}" :force-expanded="getRowExpansionState('#{section[1]}')" @expansion-changed="expanded => handleCellExpansion('#{section[1]}')" ) - if transcript_sections.count > 1 .mb-2 - else .text-muted.fst-italic | (Excerpt #{i+1}) No Data Found - else .text-muted.fst-italic | No Data Found .reports-table v-show="isAggregateView" ref="aggregateTable" table.table-striped.table.table-bordered.table-responsive style="transform: translate3d(0, 0, 0);" thead.fs-12 tr th button.btn.btn-sm.btn-outline-primary.py-1.px-2.fs-12[ @click="toggleAllInTable" style="width: fit-content; min-height: 22px; line-height: 1.2" ] vue-feather.mt-1[ :type="tableExpanded ? 'minimize-2' : 'maximize-2'" size="16" ] th.p-4 Aggregate Summary tbody.fs-12 - @sections.each do |section| tr td.p-4.align-top.semi-bold .sticky-row-header expandable-row[ :section-name="'#{section[0]}'" :section-id="'#{section[1]}'" :parent-expanded="tableExpanded" @toggle-row="expanded => toggleRowExpansion('#{section[1]}', expanded)" ] td.align-top.p-4 - section_summary = @section_summaries_by_id&.dig(section[1])&.last - if section_summary expandable-text( :text="#{section_summary.summary_markdown.to_json}" :force-expanded="getRowExpansionState('#{section[1]}')" @expansion-changed="expanded => handleCellExpansion('#{section[1]}')" ) - else .text-muted.fst-italic | No Data Found - else .text-center.my-5 .custom-card .card.border-primary.shadow-sm.mx-auto style="max-width: 500px" .card-body.p-5 i.bi.bi-inbox.text-primary.fs-1.mb-3 h5.card-title.text-primary.mb-3 No Section Data Available p.card-text.text-muted.mb-0 There are currently no items to display in this table. / ========================================================================= / INSIGHTS REPORT BLOCK / ========================================================================= div v-if="isInsightsReport" .reports-table v-show="isRawView" ref="rawTable" table.table.table-striped.table.table-bordered.table-responsive thead.fs-12 tr th button.btn.btn-sm.btn-outline-primary.py-1.px-2.fs-12[ @click="toggleAllInTable" style="width: fit-content; min-height: 22px; line-height: 1.2" ] vue-feather.mt-1[ :type="tableExpanded ? 'minimize-2' : 'maximize-2'" size="16" ] - @insights_respondents.each do |respondent| th.p-4 style="min-width: 300px;" = link_to respondent.name, [respondent.project, respondent.respondent_category, respondent], target: "_blank" - unless respondent.tags.empty? .d-flex.flex-wrap.gap-1.mt-1 - respondent.tags.includes(:tag_category).each do |tag| span.badge.bg-secondary.me-2.text-black.fs-10 = tag.tag_category.name |: = tag.name tbody.fs-12 - @insights_grouped_data.each do |group| - if group[:section].present? tr td.bg-light.text-primary.fw-bold.p-3 colspan="#{@insights_respondents.size + 1}" style="background-color: #f8f9fa !important;" .d-flex.align-items-center vue-feather.me-2 type="layout" size="18" span = group[:section].name - elsif @insights_grouped_data.size > 1 tr td.bg-light.text-primary.fw-bold.p-3 colspan="#{@insights_respondents.size + 1}" style="background-color: #f8f9fa !important;" .d-flex.align-items-center vue-feather.me-2 type="inbox" size="18" span General / Un-sectioned - group[:questions_data].each do |qd| - question = qd[:question] - row_id = qd[:row_id] tr td.p-4.align-top.semi-bold .sticky-row-header expandable-row[ :section-name="'#{question.question.gsub("'", "")}'" :section-id="'#{row_id}'" :parent-expanded="tableExpanded" @toggle-row="expanded => toggleRowExpansion('#{row_id}', expanded)" ] - @insights_respondents.each do |r| - insight = qd[:insights_by_respondent][r.id] td - if insight && !insight.sources.blank? expandable-text( :text="#{insight.sources.to_json}" :force-expanded="getRowExpansionState('#{row_id}')" @expansion-changed="expanded => handleCellExpansion('#{row_id}')" ) - else .text-muted.fst-italic AI could not find a relevant answer from the source data .reports-table v-show="isAnalysisView" ref="analysisTable" table.table.table-striped.table.table-bordered.table-responsive thead.fs-12 tr th button.btn.btn-sm.btn-outline-primary.py-1.px-2.fs-12[ @click="toggleAllInTable" style="width: fit-content; min-height: 22px; line-height: 1.2" ] vue-feather.mt-1[ :type="tableExpanded ? 'minimize-2' : 'maximize-2'" size="16" ] - @insights_respondents.each do |respondent| th.p-4 style="min-width: 300px;" = link_to respondent.name, [respondent.project, respondent.respondent_category, respondent], target: "_blank" - unless respondent.tags.empty? .d-flex.flex-wrap.gap-1.mt-1 - respondent.tags.includes(:tag_category).each do |tag| span.badge.bg-secondary.me-2.text-black.fs-10 = tag.tag_category.name |: = tag.name tbody.fs-12 - @insights_grouped_data.each do |group| - if group[:section].present? tr td.bg-light.text-primary.fw-bold.p-3 colspan="#{@insights_respondents.size + 1}" style="background-color: #f8f9fa !important;" .d-flex.align-items-center vue-feather.me-2 type="layout" size="18" span = group[:section].name - elsif @insights_grouped_data.size > 1 tr td.bg-light.text-primary.fw-bold.p-3 colspan="#{@insights_respondents.size + 1}" style="background-color: #f8f9fa !important;" .d-flex.align-items-center vue-feather.me-2 type="inbox" size="18" span General / Un-sectioned - group[:questions_data].each do |qd| - question = qd[:question] - row_id = qd[:row_id] tr td.p-4.align-top.semi-bold .sticky-row-header expandable-row[ :section-name="'#{question.question.gsub("'", "")}'" :section-id="'#{row_id}'" :parent-expanded="tableExpanded" @toggle-row="expanded => toggleRowExpansion('#{row_id}', expanded)" ] - @insights_respondents.each do |r| - insight = qd[:insights_by_respondent][r.id] td - if insight && !insight.ai_summary.blank? expandable-text( :text="#{insight.ai_summary_markdown.to_json}" :force-expanded="getRowExpansionState('#{row_id}')" @expansion-changed="expanded => handleCellExpansion('#{row_id}')" ) - else .text-muted.fst-italic AI could not find a relevant answer from the source data .reports-table v-show="isAggregateView" ref="aggregateTable" table.table.table-striped.table.table-bordered.table-responsive thead.fs-12 tr th button.btn.btn-sm.btn-outline-primary.py-1.px-2.fs-12[ @click="toggleAllInTable" style="width: fit-content; min-height: 22px; line-height: 1.2" ] vue-feather.mt-1[ :type="tableExpanded ? 'minimize-2' : 'maximize-2'" size="16" ] th.p-4 Summary tbody.fs-12 - @insights_grouped_data.each do |group| - if group[:section].present? tr td.bg-light.text-primary.fw-bold.p-3 colspan="2" style="background-color: #f8f9fa !important;" .d-flex.align-items-center vue-feather.me-2 type="layout" size="18" span = group[:section].name - elsif @insights_grouped_data.size > 1 tr td.bg-light.text-primary.fw-bold.p-3 colspan="2" style="background-color: #f8f9fa !important;" .d-flex.align-items-center vue-feather.me-2 type="inbox" size="18" span General / Un-sectioned - group[:questions_data].each do |qd| - question = qd[:question] - row_id = qd[:row_id] tr td.p-4.align-top.semi-bold .sticky-row-header expandable-row[ :section-name="'#{question.question.gsub("'", "")}'" :section-id="'#{row_id}'" :parent-expanded="tableExpanded" @toggle-row="expanded => toggleRowExpansion('#{row_id}', expanded)" ] td.align-top.p-4 - insight_summary = qd[:summary]&.summary_markdown&.to_json - if insight_summary.present? && qd[:summary].summary_markdown.present? expandable-text( :text="#{insight_summary}" :force-expanded="getRowExpansionState('#{row_id}')" @expansion-changed="expanded => handleCellExpansion('#{row_id}')" ) - else .text-muted.fst-italic No Summary Data / ========================================================================= / THEMES REPORT BLOCK / ========================================================================= div v-if="isThemesReport" - if @respondent_category.highlight_themes.joins(:transcript_highlights).exists? .reports-table v-show="isHighlightView" ref="highlightTable" table.table-striped.table.table-bordered.table-responsive style="transform: translate3d(0, 0, 0);" thead.fs-12 tr th button.btn.btn-sm.btn-outline-primary.py-1.px-2.fs-12[ @click="toggleAllInTable" style="width: fit-content; min-height: 22px; line-height: 1.2" ] vue-feather.mt-1[ :type="tableExpanded ? 'minimize-2' : 'maximize-2'" size="16" ] - @respondents_with_highlights.each do |respondent| th.p-4 style="min-width: 300px;" = link_to respondent.name, [respondent.project, respondent.respondent_category, respondent], target: "_blank" - unless respondent.tags.empty? .d-flex.flex-wrap.gap-1.mt-1 - respondent.tags.includes(:tag_category).each do |tag| span.badge.bg-secondary.me-2.text-black.fs-10 = tag.tag_category.name |: = tag.name tbody.fs-12 - @highlight_table_data.each do |section_data| - section_data[:themes_data].each do |theme_data| tr td.p-4.align-top.semi-bold .sticky-row-header expandable-row[ :section-name="'#{section_data[:section].name} | #{theme_data[:theme].theme}'" :section-id="'#{theme_data[:theme].id}'" :parent-expanded="tableExpanded" @toggle-row="expanded => toggleRowExpansion('#{theme_data[:theme].id}', expanded)" ] - @respondents_with_highlights.each do |respondent| - respondent_data = theme_data[:highlights_by_respondent].find { |h| h[:respondent_id] == respondent.id } td.align-top.p-4 - if respondent_data&.dig(:highlights)&.present? - respondent_data[:highlights].each_with_index do |highlight, index| .mb-3 class="#{'border-bottom' unless index == respondent_data[:highlights].length - 1}" expandable-text( :text="#{highlight.verbose_to_text.to_json}" :force-expanded="getRowExpansionState('#{theme_data[:theme].id}')" @expansion-changed="expanded => handleCellExpansion('#{theme_data[:theme].id}')" ) - else .text-muted.fst-italic | No Data Found .reports-table v-show="isUnthemedView" ref="unthemedTable" table.table-striped.table.table-bordered.table-responsive style="transform: translate3d(0, 0, 0);" thead.fs-12 tr th button.btn.btn-sm.btn-outline-primary.py-1.px-2.fs-12[ @click="toggleAllInTable" style="width: fit-content; min-height: 22px; line-height: 1.2" ] vue-feather.mt-1[ :type="tableExpanded ? 'minimize-2' : 'maximize-2'" size="16" ] - @respondents_with_highlights_unthemed.each do |respondent| th.p-4 style="min-width: 300px;" = link_to respondent.name, [respondent.project, respondent.respondent_category, respondent], target: "_blank" - unless respondent.tags.empty? .d-flex.flex-wrap.gap-1.mt-1 - respondent.tags.includes(:tag_category).each do |tag| span.badge.bg-secondary.me-2.text-black.fs-10 = tag.tag_category.name |: = tag.name tbody.fs-12 - @unthemed_highlight_table_data.each do |section_data| tr td.p-4.align-top.semi-bold .sticky-row-header expandable-row[ :section-name="'#{section_data[:section].name}'" :section-id="'#{section_data[:section].id}'" :parent-expanded="tableExpanded" @toggle-row="expanded => toggleRowExpansion('#{section_data[:section].id}', expanded)" ] - @respondents_with_highlights_unthemed.each do |respondent| - respondent_data = section_data[:highlights_by_respondent].find { |h| h[:respondent_id] == respondent.id } td.align-top.p-4 - if respondent_data&.dig(:highlights)&.present? - respondent_data[:highlights].each_with_index do |highlight, index| .mb-3 class="#{'border-bottom' unless index == respondent_data[:highlights].length - 1}" expandable-text( :text="#{highlight.verbose_to_text.to_json}" :force-expanded="getRowExpansionState('#{section_data[:section].id}')" @expansion-changed="expanded => handleCellExpansion('#{section_data[:section].id}')" ) - else .text-muted.fst-italic | No Data Found .reports-table v-show="isRawView" ref="rawTable" table.table-striped.table.table-bordered.table-responsive style="transform: translate3d(0, 0, 0);" thead.fs-12 tr th button.btn.btn-sm.btn-outline-primary.py-1.px-2.fs-12[ @click="toggleAllInTable" style="width: fit-content; min-height: 22px; line-height: 1.2" ] vue-feather.mt-1[ :type="tableExpanded ? 'minimize-2' : 'maximize-2'" size="16" ] - @respondents_with_highlights_raw.each do |respondent| th.p-4 style="min-width: 300px;" = link_to respondent.name, [respondent.project, respondent.respondent_category, respondent], target: "_blank" - unless respondent.tags.empty? .d-flex.flex-wrap.gap-1.mt-1 - respondent.tags.includes(:tag_category).each do |tag| span.badge.bg-secondary.me-2.text-black.fs-10 = tag.tag_category.name |: = tag.name tbody.fs-12 - @raw_highlight_data.each do |theme_data| tr td.p-4.align-top.semi-bold .sticky-row-header expandable-row[ :section-name="'#{theme_data[:theme].theme}'" :section-id="'#{theme_data[:theme].id}'" :parent-expanded="tableExpanded" @toggle-row="expanded => toggleRowExpansion('#{theme_data[:theme].id}', expanded)" ] - @respondents_with_highlights_raw.each do |respondent| - respondent_data = theme_data[:highlights_by_respondent].find { |h| h[:respondent_id] == respondent.id } td.align-top.p-4 - if respondent_data&.dig(:highlights)&.present? - respondent_data[:highlights].each_with_index do |highlight, index| .mb-3 class="#{'border-bottom' unless index == respondent_data[:highlights].length - 1}" expandable-text( :text="#{highlight.verbose_to_text.to_json}" :force-expanded="getRowExpansionState('#{theme_data[:theme].id}')" @expansion-changed="expanded => handleCellExpansion('#{theme_data[:theme].id}')" ) - else .text-muted.fst-italic | No Data Found - else .text-center.my-5 .custom-card .card.border-primary.shadow-sm.mx-auto style="max-width: 500px" .card-body.p-5 i.bi.bi-inbox.text-primary.fs-1.mb-3 h5.card-title.text-primary.mb-3 No Theme Data Available p.card-text.text-muted.mb-0 There are currently no items to display in this table.