Skip to content

Commit 5594fcf

Browse files
kommunarrabsidue
andauthored
Keyword search history (#6414)
* Add search history DB integration * Implement search history display logic and UI * Modify search cache removal setting to remove search history as well * Exclude current search route from history suggestions and populate input with matching query * Modify new labels for clarity * Fix issues detected during review Fix focus being lost for a second during searching of search history entry causing clear text button to phase away for a moment. Fix clear text button event not being noticed by the logic in top-nav. Fix spacebar error issue by adding check in updateVisibleDataList function. * Implement fixes from code review Fixes clear text button to appear and stay visible when the dropdown options are visible in an ft-input. Fixes updateVisibleDataList not using trim(), thus incorrectly causing filtering of search history when space bar was used. * Update logic to allowing storing and searching by name rather than by route This is much more efficient for search history particularly. No need for app-specific routes and easier operations & logic due to name being the primary key for search history entries. This still allows for the route to be used as the _id for different kinds of search history (i.e., bookmarks) that could be added in the future. * Add back clear statement * Fix clear text button not working or appearing as active when arrowing through search history results * Add 'Remove' option * Implement search history entries showing up alongside YT search suggestions as queries are being typed * Improve code commenting * Implement code review changes Fix preventDefault being called for arrow left/right in search input. Revert ellipsis changes for overly long search results. Adjust matching search history logic to be non-heuristic. * Fix text overflow issue with long search history entries * Remove 'name' field and unused DB methods * Implement 'Remember Search History' setting and rename 'Remember History' to 'Remember Watch History' * Apply suggestions from code review Co-authored-by: absidue <[email protected]> * Update to not show search history suggestions if 'Remember Search History' is disabled * Update logic to make 'Enable Search Suggestions' being false still allow showing search history results * Revert hiding old search history entries if rememberSearchHistory is disabled * Fix searchOptions not closing in edge case Bug scenario: 1. click search history entry, 2. click clear text button, 3. see state of searchOptions not being closeable until re-interacting with the input * Update src/renderer/views/Search/Search.js Co-authored-by: absidue <[email protected]> * Add bolding to selected/focused 'Remove' button --------- Co-authored-by: absidue <[email protected]>
1 parent 9d286fe commit 5594fcf

File tree

23 files changed

+476
-55
lines changed

23 files changed

+476
-55
lines changed

src/constants.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ const IpcChannels = {
2626
DB_HISTORY: 'db-history',
2727
DB_PROFILES: 'db-profiles',
2828
DB_PLAYLISTS: 'db-playlists',
29+
DB_SEARCH_HISTORY: 'db-search-history',
2930
DB_SUBSCRIPTION_CACHE: 'db-subscription-cache',
3031

3132
SYNC_SETTINGS: 'sync-settings',
3233
SYNC_HISTORY: 'sync-history',
34+
SYNC_SEARCH_HISTORY: 'sync-search-history',
3335
SYNC_PROFILES: 'sync-profiles',
3436
SYNC_PLAYLISTS: 'sync-playlists',
3537
SYNC_SUBSCRIPTION_CACHE: 'sync-subscription-cache',
@@ -193,6 +195,12 @@ const PLAYLIST_HEIGHT_FORCE_LIST_THRESHOLD = 500
193195
// YouTube search character limit is 100 characters
194196
const SEARCH_CHAR_LIMIT = 100
195197

198+
// max # of results we show for search suggestions
199+
const SEARCH_RESULTS_DISPLAY_LIMIT = 14
200+
201+
// max # of search history results we show when mixed with YT search suggestions
202+
const MIXED_SEARCH_HISTORY_ENTRIES_DISPLAY_LIMIT = 4
203+
196204
// Displayed on the about page and used in the main.js file to only allow bitcoin URLs with this wallet address to be opened
197205
const ABOUT_BITCOIN_ADDRESS = '1Lih7Ho5gnxb1CwPD4o59ss78pwo2T91eS'
198206

@@ -205,5 +213,7 @@ export {
205213
MOBILE_WIDTH_THRESHOLD,
206214
PLAYLIST_HEIGHT_FORCE_LIST_THRESHOLD,
207215
SEARCH_CHAR_LIMIT,
216+
SEARCH_RESULTS_DISPLAY_LIMIT,
217+
MIXED_SEARCH_HISTORY_ENTRIES_DISPLAY_LIMIT,
208218
ABOUT_BITCOIN_ADDRESS,
209219
}

src/datastores/handlers/base.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,24 @@ class Playlists {
226226
}
227227
}
228228

229+
class SearchHistory {
230+
static find() {
231+
return db.searchHistory.findAsync({}).sort({ lastUpdatedAt: -1 })
232+
}
233+
234+
static upsert(searchHistoryEntry) {
235+
return db.searchHistory.updateAsync({ _id: searchHistoryEntry._id }, searchHistoryEntry, { upsert: true })
236+
}
237+
238+
static delete(_id) {
239+
return db.searchHistory.removeAsync({ _id: _id })
240+
}
241+
242+
static deleteAll() {
243+
return db.searchHistory.removeAsync({}, { multi: true })
244+
}
245+
}
246+
229247
class SubscriptionCache {
230248
static find() {
231249
return db.subscriptionCache.findAsync({})
@@ -311,6 +329,7 @@ function compactAllDatastores() {
311329
db.history.compactDatafileAsync(),
312330
db.profiles.compactDatafileAsync(),
313331
db.playlists.compactDatafileAsync(),
332+
db.searchHistory.compactDatafileAsync(),
314333
db.subscriptionCache.compactDatafileAsync(),
315334
])
316335
}
@@ -320,6 +339,7 @@ export {
320339
History as history,
321340
Profiles as profiles,
322341
Playlists as playlists,
342+
SearchHistory as searchHistory,
323343
SubscriptionCache as subscriptionCache,
324344

325345
compactAllDatastores,

src/datastores/handlers/electron.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,36 @@ class Playlists {
218218
}
219219
}
220220

221+
class SearchHistory {
222+
static find() {
223+
return ipcRenderer.invoke(
224+
IpcChannels.DB_SEARCH_HISTORY,
225+
{ action: DBActions.GENERAL.FIND }
226+
)
227+
}
228+
229+
static upsert(searchHistoryEntry) {
230+
return ipcRenderer.invoke(
231+
IpcChannels.DB_SEARCH_HISTORY,
232+
{ action: DBActions.GENERAL.UPSERT, data: searchHistoryEntry }
233+
)
234+
}
235+
236+
static delete(_id) {
237+
return ipcRenderer.invoke(
238+
IpcChannels.DB_SEARCH_HISTORY,
239+
{ action: DBActions.GENERAL.DELETE, data: _id }
240+
)
241+
}
242+
243+
static deleteAll() {
244+
return ipcRenderer.invoke(
245+
IpcChannels.DB_SEARCH_HISTORY,
246+
{ action: DBActions.GENERAL.DELETE_ALL }
247+
)
248+
}
249+
}
250+
221251
class SubscriptionCache {
222252
static find() {
223253
return ipcRenderer.invoke(
@@ -296,5 +326,6 @@ export {
296326
History as history,
297327
Profiles as profiles,
298328
Playlists as playlists,
329+
SearchHistory as searchHistory,
299330
SubscriptionCache as subscriptionCache,
300331
}

src/datastores/handlers/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ export {
33
history as DBHistoryHandlers,
44
profiles as DBProfileHandlers,
55
playlists as DBPlaylistHandlers,
6+
searchHistory as DBSearchHistoryHandlers,
67
subscriptionCache as DBSubscriptionCacheHandlers,
78
} from 'DB_HANDLERS_ELECTRON_RENDERER_OR_WEB'

src/datastores/handlers/web.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ class Settings {
2424
export { Settings as settings }
2525

2626
// These classes don't require any changes from the base classes, so can be exported as-is.
27-
export { history, profiles, playlists, subscriptionCache } from './base'
27+
export { history, profiles, playlists, searchHistory, subscriptionCache } from './base'

src/datastores/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ export const settings = new Datastore({ filename: dbPath('settings'), autoload:
2626
export const profiles = new Datastore({ filename: dbPath('profiles'), autoload: true })
2727
export const playlists = new Datastore({ filename: dbPath('playlists'), autoload: true })
2828
export const history = new Datastore({ filename: dbPath('history'), autoload: true })
29+
export const searchHistory = new Datastore({ filename: dbPath('search-history'), autoload: true })
2930
export const subscriptionCache = new Datastore({ filename: dbPath('subscription-cache'), autoload: true })

src/main/index.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,51 @@ function runApp() {
13431343

13441344
// *********** //
13451345

1346+
// ************** //
1347+
// Search History
1348+
ipcMain.handle(IpcChannels.DB_SEARCH_HISTORY, async (event, { action, data }) => {
1349+
try {
1350+
switch (action) {
1351+
case DBActions.GENERAL.FIND:
1352+
return await baseHandlers.searchHistory.find()
1353+
1354+
case DBActions.GENERAL.UPSERT:
1355+
await baseHandlers.searchHistory.upsert(data)
1356+
syncOtherWindows(
1357+
IpcChannels.SYNC_SEARCH_HISTORY,
1358+
event,
1359+
{ event: SyncEvents.GENERAL.UPSERT, data }
1360+
)
1361+
return null
1362+
1363+
case DBActions.GENERAL.DELETE:
1364+
await baseHandlers.searchHistory.delete(data)
1365+
syncOtherWindows(
1366+
IpcChannels.SYNC_SEARCH_HISTORY,
1367+
event,
1368+
{ event: SyncEvents.GENERAL.DELETE, data }
1369+
)
1370+
return null
1371+
1372+
case DBActions.GENERAL.DELETE_ALL:
1373+
await baseHandlers.searchHistory.deleteAll()
1374+
syncOtherWindows(
1375+
IpcChannels.SYNC_SEARCH_HISTORY,
1376+
event,
1377+
{ event: SyncEvents.GENERAL.DELETE_ALL }
1378+
)
1379+
return null
1380+
1381+
default:
1382+
// eslint-disable-next-line no-throw-literal
1383+
throw 'invalid search history db action'
1384+
}
1385+
} catch (err) {
1386+
if (typeof err === 'string') throw err
1387+
else throw err.toString()
1388+
}
1389+
})
1390+
13461391
// *********** //
13471392
// Profiles
13481393
ipcMain.handle(IpcChannels.DB_SUBSCRIPTION_CACHE, async (event, { action, data }) => {

src/renderer/App.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ export default defineComponent({
194194
this.grabHistory()
195195
this.grabAllPlaylists()
196196
this.grabAllSubscriptions()
197+
this.grabSearchHistoryEntries()
197198

198199
if (process.env.IS_ELECTRON) {
199200
ipcRenderer = require('electron').ipcRenderer
@@ -580,6 +581,7 @@ export default defineComponent({
580581
'grabHistory',
581582
'grabAllPlaylists',
582583
'grabAllSubscriptions',
584+
'grabSearchHistoryEntries',
583585
'getYoutubeUrlInfo',
584586
'getExternalPlayerCmdArgumentsData',
585587
'fetchInvidiousInstances',

src/renderer/components/ft-input/ft-input.css

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@ body[dir='rtl'] .ft-input-component.search.showClearTextButton:focus-within .inp
3131
padding-inline-start: 46px;
3232
}
3333

34-
.ft-input-component:focus-within .clearInputTextButton {
34+
.ft-input-component:focus-within .clearInputTextButton,
35+
.ft-input-component.showOptions .clearInputTextButton {
3536
opacity: 0.5;
3637
}
3738

38-
.clearTextButtonVisible .clearInputTextButton.visible,
39-
.ft-input-component:focus-within .clearInputTextButton.visible {
39+
40+
.ft-input-component.inputDataPresent .clearInputTextButton.visible,
41+
.clearTextButtonVisible:not(.showOptions) .clearInputTextButton.visible,
42+
.ft-input-component:focus-within:not(.showOptions) .clearInputTextButton.visible {
4043
cursor: pointer;
4144
opacity: 1;
4245
}
@@ -200,10 +203,30 @@ body[dir='rtl'] .ft-input-component.search.showClearTextButton:focus-within .inp
200203
}
201204

202205
.list li {
203-
display: block;
206+
display: flex;
207+
justify-content: space-between;
204208
padding-block: 0;
205-
padding-inline: 15px;
206209
line-height: 2rem;
210+
padding-inline: 15px;
211+
}
212+
213+
.searchResultIcon {
214+
opacity: 0.6;
215+
padding-inline-end: 10px;
216+
inline-size: 16px;
217+
block-size: 16px;
218+
}
219+
220+
.removeButton {
221+
text-decoration: none;
222+
float: var(--float-right-ltr-rtl-value);
223+
font-size: 13px;
224+
}
225+
226+
.removeButton:hover,
227+
.removeButtonSelected {
228+
text-decoration: underline;
229+
font-weight: bold;
207230
}
208231

209232
.hover {

0 commit comments

Comments
 (0)