From b2b877a8c3e1f42e13a246a7714656f820a28145 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Thu, 22 Jun 2023 11:25:01 +0300 Subject: [PATCH] Fix: (UI) Maintain search type and parameters on repeat search --- .../src/History/Details/HistoryDetails.js | 6 +- frontend/src/History/HistoryRow.js | 230 ++++++------------ frontend/src/History/HistoryRowConnector.js | 4 +- frontend/src/History/historyDataTypes.js | 17 ++ .../034_history_fix_data_titlesFixture.cs | 91 +++++++ .../Migration/034_history_fix_data_titles.cs | 66 +++++ src/NzbDrone.Core/History/HistoryService.cs | 4 +- 7 files changed, 255 insertions(+), 163 deletions(-) create mode 100644 frontend/src/History/historyDataTypes.js create mode 100644 src/NzbDrone.Core.Test/Datastore/Migration/034_history_fix_data_titlesFixture.cs create mode 100644 src/NzbDrone.Core/Datastore/Migration/034_history_fix_data_titles.cs diff --git a/frontend/src/History/Details/HistoryDetails.js b/frontend/src/History/Details/HistoryDetails.js index 63543f040..23dc0b0dd 100644 --- a/frontend/src/History/Details/HistoryDetails.js +++ b/frontend/src/History/Details/HistoryDetails.js @@ -76,7 +76,7 @@ function HistoryDetails(props) { if (eventType === 'releaseGrabbed') { const { source, - title, + grabTitle, url } = data; @@ -101,8 +101,8 @@ function HistoryDetails(props) { { !!data && } diff --git a/frontend/src/History/HistoryRow.js b/frontend/src/History/HistoryRow.js index 1370257ad..1a7dec144 100644 --- a/frontend/src/History/HistoryRow.js +++ b/frontend/src/History/HistoryRow.js @@ -8,10 +8,31 @@ import { icons } from 'Helpers/Props'; import CapabilitiesLabel from 'Indexer/Index/Table/CapabilitiesLabel'; import translate from 'Utilities/String/translate'; import HistoryDetailsModal from './Details/HistoryDetailsModal'; +import * as historyDataTypes from './historyDataTypes'; import HistoryEventTypeCell from './HistoryEventTypeCell'; import HistoryRowParameter from './HistoryRowParameter'; import styles from './HistoryRow.css'; +const historyParameters = [ + { key: historyDataTypes.IMDB_ID, title: 'IMDb' }, + { key: historyDataTypes.TMDB_ID, title: 'TMDb' }, + { key: historyDataTypes.TVDB_ID, title: 'TVDb' }, + { key: historyDataTypes.TRAKT_ID, title: 'Trakt' }, + { key: historyDataTypes.R_ID, title: 'TvRage' }, + { key: historyDataTypes.TVMAZE_ID, title: 'TvMaze' }, + { key: historyDataTypes.SEASON, title: translate('Season') }, + { key: historyDataTypes.EPISODE, title: translate('Episode') }, + { key: historyDataTypes.ARTIST, title: translate('Artist') }, + { key: historyDataTypes.ALBUM, title: translate('Album') }, + { key: historyDataTypes.LABEL, title: translate('Label') }, + { key: historyDataTypes.TRACK, title: translate('Track') }, + { key: historyDataTypes.YEAR, title: translate('Year') }, + { key: historyDataTypes.GENRE, title: translate('Genre') }, + { key: historyDataTypes.AUTHOR, title: translate('Author') }, + { key: historyDataTypes.TITLE, title: translate('Title') }, + { key: historyDataTypes.PUBLISHER, title: translate('Publisher') } +]; + class HistoryRow extends Component { // @@ -44,15 +65,52 @@ class HistoryRow extends Component { data } = this.props; + const { query, queryType } = data; + + let searchQuery = query; let categories = []; if (data.categories) { - categories = data.categories.split(',').map((item) => { - return parseInt(item); - }); + categories = data.categories.split(',').map((item) => parseInt(item)); + } + + const searchParams = [ + historyDataTypes.IMDB_ID, + historyDataTypes.TMDB_ID, + historyDataTypes.TVDB_ID, + historyDataTypes.TRAKT_ID, + historyDataTypes.R_ID, + historyDataTypes.TVMAZE_ID, + historyDataTypes.SEASON, + historyDataTypes.EPISODE, + historyDataTypes.ARTIST, + historyDataTypes.ALBUM, + historyDataTypes.LABEL, + historyDataTypes.TRACK, + historyDataTypes.YEAR, + historyDataTypes.GENRE, + historyDataTypes.AUTHOR, + historyDataTypes.TITLE, + historyDataTypes.PUBLISHER + ] + .reduce((acc, key) => { + if (key in data && data[key].length > 0) { + const value = data[key]; + + acc.push({ key, value }); + } + + return acc; + }, []) + .map((item) => `{${item.key}:${item.value}}`) + .join('') + ; + + if (searchParams.length > 0) { + searchQuery += `${searchParams}`; } - this.props.onSearchPress(data.query, indexer.id, categories); + this.props.onSearchPress(searchQuery, indexer.id, categories, queryType); }; onDetailsPress = () => { @@ -84,6 +142,8 @@ class HistoryRow extends Component { return null; } + const parameters = historyParameters.filter((parameter) => parameter.key in data && data[parameter.key]); + return ( { @@ -137,158 +197,16 @@ class HistoryRow extends Component { key={name} className={styles.parameters} > - { - data.imdbId ? - : - null - } - - { - data.tmdbId ? - : - null - } - - { - data.tvdbId ? - : - null - } - - { - data.traktId ? + {parameters.map((parameter) => { + return ( : - null - } - - { - data.rId ? - : - null - } - - { - data.tvMazeId ? - : - null - } - - { - data.season ? - : - null - } - - { - data.episode ? - : - null - } - - { - data.artist ? - : - null - } - - { - data.album ? - : - null - } - - { - data.label ? - : - null - } - - { - data.track ? - : - null - } - - { - data.year ? - : - null - } - - { - data.genre ? - : - null - } - - { - data.author ? - : - null - } - - { - data.bookTitle ? - : - null - } - - { - data.publisher ? - : - null + key={parameter.key} + title={parameter.title} + value={data[parameter.key]} + /> + ); } + )} ); } @@ -300,8 +218,8 @@ class HistoryRow extends Component { className={styles.indexer} > { - data.title ? - data.title : + data.grabTitle ? + data.grabTitle : null } diff --git a/frontend/src/History/HistoryRowConnector.js b/frontend/src/History/HistoryRowConnector.js index 2d01a2d19..341444f2e 100644 --- a/frontend/src/History/HistoryRowConnector.js +++ b/frontend/src/History/HistoryRowConnector.js @@ -48,8 +48,8 @@ class HistoryRowConnector extends Component { // // Listeners - onSearchPress = (term, indexerId, categories) => { - this.props.setSearchDefault({ searchQuery: term, searchIndexerIds: [indexerId], searchCategories: categories }); + onSearchPress = (term, indexerId, categories, type) => { + this.props.setSearchDefault({ searchQuery: term, searchIndexerIds: [indexerId], searchCategories: categories, searchType: type }); this.props.push(`${window.Prowlarr.urlBase}/search`); }; diff --git a/frontend/src/History/historyDataTypes.js b/frontend/src/History/historyDataTypes.js new file mode 100644 index 000000000..5d2513d2e --- /dev/null +++ b/frontend/src/History/historyDataTypes.js @@ -0,0 +1,17 @@ +export const IMDB_ID = 'imdbId'; +export const TMDB_ID = 'tmdbId'; +export const TVDB_ID = 'tvdbId'; +export const TRAKT_ID = 'traktId'; +export const R_ID = 'rId'; +export const TVMAZE_ID = 'tvMazeId'; +export const SEASON = 'season'; +export const EPISODE = 'episode'; +export const ARTIST = 'artist'; +export const ALBUM = 'album'; +export const LABEL = 'label'; +export const TRACK = 'track'; +export const YEAR = 'year'; +export const GENRE = 'genre'; +export const AUTHOR = 'author'; +export const TITLE = 'title'; +export const PUBLISHER = 'publisher'; diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/034_history_fix_data_titlesFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/034_history_fix_data_titlesFixture.cs new file mode 100644 index 000000000..4c0a3393e --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Migration/034_history_fix_data_titlesFixture.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Datastore.Migration; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Datastore.Migration +{ + [TestFixture] + public class history_fix_data_titlesFixture : MigrationTest + { + [Test] + public void should_update_data_for_book_search() + { + var db = WithMigrationTestDb(c => + { + c.Insert.IntoTable("History").Row(new + { + IndexerId = 1, + Date = DateTime.UtcNow, + Data = new + { + Author = "Fake Author", + BookTitle = "Fake Book Title", + Publisher = "", + Year = "", + Genre = "", + Query = "", + QueryType = "book", + Source = "Prowlarr", + Host = "localhost" + }.ToJson(), + EventType = 2, + Successful = true + }); + }); + + var items = db.Query("SELECT * FROM \"History\""); + + items.Should().HaveCount(1); + + items.First().Data.Should().NotContainKey("bookTitle"); + items.First().Data.Should().ContainKey("title"); + items.First().Data.GetValueOrDefault("title").Should().Be("Fake Book Title"); + } + + [Test] + public void should_update_data_for_release_grabbed() + { + var db = WithMigrationTestDb(c => + { + c.Insert.IntoTable("History").Row(new + { + IndexerId = 1, + Date = DateTime.UtcNow, + Data = new + { + GrabMethod = "Proxy", + Title = "Fake Release Title", + Source = "Prowlarr", + Host = "localhost" + }.ToJson(), + EventType = 1, + Successful = true + }); + }); + + var items = db.Query("SELECT * FROM \"History\""); + + items.Should().HaveCount(1); + + items.First().Data.Should().NotContainKey("title"); + items.First().Data.Should().ContainKey("grabTitle"); + items.First().Data.GetValueOrDefault("grabTitle").Should().Be("Fake Release Title"); + } + } + + public class HistoryDefinition34 + { + public int Id { get; set; } + public int IndexerId { get; set; } + public DateTime Date { get; set; } + public Dictionary Data { get; set; } + public int EventType { get; set; } + public string DownloadId { get; set; } + public bool Successful { get; set; } + } +} diff --git a/src/NzbDrone.Core/Datastore/Migration/034_history_fix_data_titles.cs b/src/NzbDrone.Core/Datastore/Migration/034_history_fix_data_titles.cs new file mode 100644 index 000000000..e034ca5c8 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/034_history_fix_data_titles.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using System.Data; +using Dapper; +using FluentMigrator; +using Newtonsoft.Json.Linq; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(034)] + public class history_fix_data_titles : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Execute.WithConnection(MigrateHistoryDataTitle); + } + + private void MigrateHistoryDataTitle(IDbConnection conn, IDbTransaction tran) + { + var updatedHistory = new List(); + + using (var selectCommand = conn.CreateCommand()) + { + selectCommand.Transaction = tran; + selectCommand.CommandText = "SELECT \"Id\", \"Data\" FROM \"History\""; + + using var reader = selectCommand.ExecuteReader(); + + while (reader.Read()) + { + var id = reader.GetInt32(0); + var data = reader.GetString(1); + + if (!string.IsNullOrWhiteSpace(data)) + { + var jsonObject = Json.Deserialize(data); + + if (jsonObject.ContainsKey("title")) + { + jsonObject.Add("grabTitle", jsonObject.Value("title")); + jsonObject.Remove("title"); + } + + if (jsonObject.ContainsKey("bookTitle")) + { + jsonObject.Add("title", jsonObject.Value("bookTitle")); + jsonObject.Remove("bookTitle"); + } + + data = jsonObject.ToJson(); + + updatedHistory.Add(new + { + Id = id, + Data = data + }); + } + } + } + + var updateHistorySql = "UPDATE \"History\" SET \"Data\" = @Data WHERE \"Id\" = @Id"; + conn.Execute(updateHistorySql, updatedHistory, transaction: tran); + } + } +} diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index cf6d97dd8..902fdf6b1 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -164,7 +164,7 @@ namespace NzbDrone.Core.History if (message.Query is BookSearchCriteria bookSearchCriteria) { history.Data.Add("Author", bookSearchCriteria.Author); - history.Data.Add("BookTitle", bookSearchCriteria.Title); + history.Data.Add("Title", bookSearchCriteria.Title); history.Data.Add("Publisher", bookSearchCriteria.Publisher); history.Data.Add("Year", bookSearchCriteria.Year?.ToString()); history.Data.Add("Genre", bookSearchCriteria.Genre); @@ -199,7 +199,7 @@ namespace NzbDrone.Core.History history.Data.Add("Source", message.Source ?? string.Empty); history.Data.Add("Host", message.Host ?? string.Empty); history.Data.Add("GrabMethod", message.Redirect ? "Redirect" : "Proxy"); - history.Data.Add("Title", message.Title); + history.Data.Add("GrabTitle", message.Title); history.Data.Add("Url", message.Url ?? string.Empty); _historyRepository.Insert(history);