5 Commits
18 changed files with 108 additions and 34 deletions
@@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableNETAnalyzers>false</EnableNETAnalyzers> <EnableNETAnalyzers>false</EnableNETAnalyzers>
<Version>1.0.2</Version> <Version>1.0.3</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -8,7 +8,7 @@ const ConcordanceAggregationItem = (props) => {
const link = isSelected ? search.getClearFilterLink('TextIds', props.filterKey) : search.getFilterLink('TextIds', props.filterKey); const link = isSelected ? search.getClearFilterLink('TextIds', props.filterKey) : search.getFilterLink('TextIds', props.filterKey);
return ( return (
<li className={styles.aggregationItem}><Link to={link}>{isSelected && <span>X - </span>}{props.title}<span className='float-end'>{props.count}</span></Link></li> <li className={styles.aggregationItem}><Link to={link}>{isSelected && <span className={styles.remove} >X</span>}<span className={styles.title}>{props.title}</span><span className={styles.count}>{props.count}</span></Link></li>
); );
}; };
@@ -7,6 +7,18 @@
a { a {
color: $text-color; color: $text-color;
display: flex;
text-decoration: none; text-decoration: none;
.remove {
margin-right: 0.8rem;
}
.title {
flex-grow: 1;
margin-right: 0.8rem;
overflow: hidden;
text-overflow: clip;
}
} }
} }
@@ -6,7 +6,7 @@ const ConcordanceAlternateSearchItem = (props) => {
const search = useSearch(); const search = useSearch();
const link = search.getAlternateSearchLink(props.search); const link = search.getAlternateSearchLink(props.search);
return ( return (
<li className={styles.alternateSearchItem}><Link to={link}>{props.title}<span className='float-end'>{props.count}</span></Link></li> <li className={styles.alternateSearchItem}><Link to={link}><span className={styles.title}>{props.title}</span><span className={styles.count}>{props.count}</span></Link></li>
); );
}; };
@@ -7,6 +7,14 @@
a { a {
color: $text-color; color: $text-color;
display: flex;
text-decoration: none; text-decoration: none;
.title {
flex-grow: 1;
margin-right: 0.8rem;
overflow: hidden;
text-overflow: clip;
}
} }
} }
@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next'; import ConcordanceDetailsTextInfo from './ConcordanceDetailsTextInfo';
import sytles from './ConcordanceDetailsText.module.scss'; import { useTranslation } from 'react-i18next';
const ConcordanceDetailsText = (props) => { const ConcordanceDetailsText = (props) => {
// Hooks // Hooks
@@ -8,22 +8,10 @@ const ConcordanceDetailsText = (props) => {
return ( return (
<> <>
<div className={sytles.textInfo}> <ConcordanceDetailsTextInfo title={t('concordance.detailsTextSource')} value={props.source} />
<h5>{t('concordance.detailsTextSource')}</h5> <ConcordanceDetailsTextInfo title={t('concordance.detailsTextYear')} value={props.year} />
<p>{props.source}</p> <ConcordanceDetailsTextInfo title={t('concordance.detailsTextTitle')} value={props.title} />
</div> <ConcordanceDetailsTextInfo title={t('concordance.detailsTextAuthor')} value={props.author} />
<div className={sytles.textInfo}>
<h5>{t('concordance.detailsTextYear')}</h5>
<p>{props.year}</p>
</div>
<div className={sytles.textInfo}>
<h5>{t('concordance.detailsTextTitle')}</h5>
<p>{props.title}</p>
</div>
<div className={sytles.textInfo}>
<h5>{t('concordance.detailsTextAuthor')}</h5>
<p>{props.author}</p>
</div>
</> </>
); );
}; };
@@ -0,0 +1,15 @@
import styles from './ConcordanceDetailsTextInfo.module.scss';
const ConcordanceDetailsTextInfo = (props) => {
var title = props.title;
var value = props.value;
if (value) {
return (<div className={styles.textInfo}>
<h5>{title}</h5>
<p>{value}</p>
</div>);
}
};
export default ConcordanceDetailsTextInfo;
@@ -6,8 +6,8 @@ const ConcordanceListItem = (props) => {
return ( return (
<> <>
<div className={`row ${styles.item}`} onClick={() => { props.toggleDetails(props.index) }}> <div className={`row ${styles.item}`} onClick={() => { props.toggleDetails(props.index) }}>
<div className='col text-end'><ConcordanceTokens tokens={props.item.leftContext} />&nbsp;</div> <div className={`col ${styles.left}`}><span><ConcordanceTokens tokens={props.item.leftContext} />&nbsp;</span></div>
<div className='col'><ConcordanceTokens tokens={[props.item.centerContext]} /> <ConcordanceTokens tokens={props.item.rightContext} /></div> <div className={`col ${styles.right}`}><ConcordanceTokens tokens={[props.item.centerContext]} /> <ConcordanceTokens tokens={props.item.rightContext} /></div>
</div> </div>
{props.expanded && <ConcordanceDetails paragraphId={props.item.paragraphId} tokenOrder={props.item.centerContext.tokenOrder} onClose={() => { props.toggleDetails(null) }} />} {props.expanded && <ConcordanceDetails paragraphId={props.item.paragraphId} tokenOrder={props.item.centerContext.tokenOrder} onClose={() => { props.toggleDetails(null) }} />}
</> </>
@@ -5,4 +5,24 @@
cursor: pointer; cursor: pointer;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
padding-bottom: 0.5rem; padding-bottom: 0.5rem;
:global(.col) {
&.left,
&.right {
overflow: hidden;
white-space: nowrap;
text-overflow: clip;
}
&.left {
span {
display: inline-block;
float: right;
min-width: 100%;
overflow: visible;
text-align: right;
}
}
}
} }
@@ -12,7 +12,7 @@ const useDownload = (url) => {
var url = window.URL.createObjectURL(blob); var url = window.URL.createObjectURL(blob);
var a = document.createElement('a'); var a = document.createElement('a');
a.href = url; a.href = url;
a.download = "export.csv"; a.download = "export.txt";
document.body.appendChild(a); // we need to append the element to the dom -> otherwise it will not work in firefox document.body.appendChild(a); // we need to append the element to the dom -> otherwise it will not work in firefox
a.click(); a.click();
a.remove(); //afterwards we remove the element again a.remove(); //afterwards we remove the element again
@@ -5,7 +5,7 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableNETAnalyzers>false</EnableNETAnalyzers> <EnableNETAnalyzers>false</EnableNETAnalyzers>
<Version>1.0.2</Version> <Version>1.0.3</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableNETAnalyzers>false</EnableNETAnalyzers> <EnableNETAnalyzers>false</EnableNETAnalyzers>
<Version>1.0.2</Version> <Version>1.0.3</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableNETAnalyzers>false</EnableNETAnalyzers> <EnableNETAnalyzers>false</EnableNETAnalyzers>
<Version>1.0.2</Version> <Version>1.0.3</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableNETAnalyzers>false</EnableNETAnalyzers> <EnableNETAnalyzers>false</EnableNETAnalyzers>
<Version>1.0.2</Version> <Version>1.0.3</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableNETAnalyzers>false</EnableNETAnalyzers> <EnableNETAnalyzers>false</EnableNETAnalyzers>
<Version>1.0.2</Version> <Version>1.0.3</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -1,8 +1,11 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Rsdo.Concordancer.Core.Constants; using Rsdo.Concordancer.Core.Constants;
using Rsdo.Concordancer.Core.Interfaces; using Rsdo.Concordancer.Core.Interfaces;
using Rsdo.Concordancer.Core.Model; using Rsdo.Concordancer.Core.Model;
@@ -11,6 +14,7 @@ using Rsdo.Concordancer.Core.Search.Queries.Concordances;
using Rsdo.Concordancer.ServiceModel.Requests.Concordances; using Rsdo.Concordancer.ServiceModel.Requests.Concordances;
using Rsdo.Concordancer.ServiceModel.Shared; using Rsdo.Concordancer.ServiceModel.Shared;
using Rsdo.Concordancer.ServiceModel.Types; using Rsdo.Concordancer.ServiceModel.Types;
using Rsdo.Concordancer.Services.Framework.DbContext;
using Rsdo.Concordancer.Services.Search.QueryFactories; using Rsdo.Concordancer.Services.Search.QueryFactories;
using Rsdo.Concordancer.Services.Services.ParagraphService; using Rsdo.Concordancer.Services.Services.ParagraphService;
@@ -18,15 +22,18 @@ namespace Rsdo.Concordancer.Services.RequestHandlers.Concordances;
public class ExportConcordancesHandler : BaseSearchConcordancesHandler, IRequestHandler<ExportConcordances, ExportConcordancesResponse> public class ExportConcordancesHandler : BaseSearchConcordancesHandler, IRequestHandler<ExportConcordances, ExportConcordancesResponse>
{ {
private readonly CorpusDbContext dbContext;
private readonly IQueryFactory<ExportConcordances, ConcordancesQuery> queryFactory; private readonly IQueryFactory<ExportConcordances, ConcordancesQuery> queryFactory;
private readonly ISearchEngine searchEngine; private readonly ISearchEngine searchEngine;
public ExportConcordancesHandler( public ExportConcordancesHandler(
CorpusDbContext dbContext,
IParagraphService paragraphService, IParagraphService paragraphService,
IQueryFactory<ExportConcordances, ConcordancesQuery> queryFactory, IQueryFactory<ExportConcordances, ConcordancesQuery> queryFactory,
ISearchEngine searchEngine) ISearchEngine searchEngine)
: base(paragraphService) : base(paragraphService)
{ {
this.dbContext = dbContext;
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.searchEngine = searchEngine; this.searchEngine = searchEngine;
} }
@@ -42,6 +49,9 @@ public class ExportConcordancesHandler : BaseSearchConcordancesHandler, IRequest
// Get search items // Get search items
var items = await GetItems(query, result.EntityIds); var items = await GetItems(query, result.EntityIds);
// Get sources
var sources = await GetSources(items);
// Export // Export
var stream = new MemoryStream(); var stream = new MemoryStream();
await using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true)) await using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
@@ -52,7 +62,7 @@ public class ExportConcordancesHandler : BaseSearchConcordancesHandler, IRequest
// Write items // Write items
foreach (var item in items) foreach (var item in items)
{ {
await WriteItem(writer, item); await WriteItem(writer, item, sources[item.ParagraphId]);
} }
} }
@@ -91,16 +101,35 @@ public class ExportConcordancesHandler : BaseSearchConcordancesHandler, IRequest
await writer.WriteAsync("Iskani niz"); await writer.WriteAsync("Iskani niz");
await writer.WriteAsync("\t"); await writer.WriteAsync("\t");
await writer.WriteAsync("Desno besedilo"); await writer.WriteAsync("Desno besedilo");
await writer.WriteAsync("\t");
await writer.WriteAsync("Vir");
await writer.WriteLineAsync(); await writer.WriteLineAsync();
} }
private static async Task WriteItem(StreamWriter writer, SearchConcordancesResponseItem item) private static async Task WriteItem(StreamWriter writer, SearchConcordancesResponseItem item, string source)
{ {
await WriteContext(writer, item.LeftContext); await WriteContext(writer, item.LeftContext);
await writer.WriteAsync("\t"); await writer.WriteAsync("\t");
await writer.WriteAsync(item.CenterContext.Form); await writer.WriteAsync(item.CenterContext.Form);
await writer.WriteAsync("\t"); await writer.WriteAsync("\t");
await WriteContext(writer, item.RightContext); await WriteContext(writer, item.RightContext);
await writer.WriteAsync("\t");
await writer.WriteAsync(source);
await writer.WriteLineAsync(); await writer.WriteLineAsync();
} }
private async Task<Dictionary<Guid, string>> GetSources(List<SearchConcordancesResponseItem> items)
{
var paragraphIds = items.Select(i => i.ParagraphId).ToList();
var sources = await dbContext.Paragraph.Include(p => p.Text)
.Where(p => paragraphIds.Contains(p.Id))
.Select(
p => new
{
p.Id,
p.Text.SourceFile,
})
.ToListAsync();
return sources.ToDictionary(x => x.Id, x => Path.GetFileNameWithoutExtension(x.SourceFile));
}
} }
@@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableNETAnalyzers>false</EnableNETAnalyzers> <EnableNETAnalyzers>false</EnableNETAnalyzers>
<Version>1.0.2</Version> <Version>1.0.3</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>