Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions client/src/lib/components/SearchBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@

const sortValue = $derived(`${appState.sortBy}_${appState.sortOrder}`);

const dateFrom = $derived(appState.timestampFrom != undefined ? new Date(appState.timestampFrom * 1000).toISOString().slice(0, 10) : '');
const dateTo = $derived(appState.timestampTo != undefined ? new Date(appState.timestampTo * 1000).toISOString().slice(0, 10) : '');

function handleDateFromChange(event: Event) {
const value = (event.target as HTMLInputElement).value;
appState.timestampFrom = value ? Math.floor(new Date(value).getTime() / 1000) : undefined;
}

function handleDateToChange(event: Event) {
const value = (event.target as HTMLInputElement).value;
appState.timestampTo = value ? Math.floor(new Date(value).getTime() / 1000) : undefined;
}

function handleSortChange(event: Event) {
const target = event.target as HTMLSelectElement;
if (target) {
Expand Down Expand Up @@ -52,6 +65,12 @@
<Toggle label="Überall" bind:checked={appState.everywhere} />
<Toggle label="Zukünftige" bind:checked={appState.future} />
</div>
<div class="flex items-center gap-2">
<label for="date-from" class="date-label">Von</label>
<input id="date-from" type="date" class="date-input" value={dateFrom} onchange={handleDateFromChange} />
<label for="date-to" class="date-label">Bis</label>
<input id="date-to" type="date" class="date-input" value={dateTo} onchange={handleDateToChange} />
</div>
<div class="flex items-stretch gap-2 min-h-10">
{#if appState.viewMode === 'grid'}
<Dropdown label="Sortierung" options={sortOptions} value={sortValue} onchange={handleSortChange} />
Expand Down Expand Up @@ -97,4 +116,13 @@
.search-input-right {
@apply absolute right-0 inset-y-0 flex items-center px-4 leading-none text-gray-600 hover:text-gray-800 dark:text-gray-300 dark:hover:text-white cursor-pointer transition-opacity;
}

.date-input {
@apply h-10 rounded-md border border-gray-300 bg-gray-50 px-3 text-sm text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:focus:ring-blue-500;
color-scheme: light dark;
}

.date-label {
@apply text-sm text-gray-700 dark:text-gray-300;
}
</style>
19 changes: 18 additions & 1 deletion client/src/lib/store.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ function createAppState() {
let query = $state('');
let everywhere = $state(false);
let future = $state(true);
let timestampFrom = $state<number | undefined>(undefined);
let timestampTo = $state<number | undefined>(undefined);
let sortBy = $state<SortBy>('timestamp');
let sortOrder = $state<SortOrder>('desc');
let currentPage = $state(0);
Expand Down Expand Up @@ -55,6 +57,8 @@ function createAppState() {
sortBy,
sortOrder,
future,
timestamp_from: timestampFrom,
timestamp_to: timestampTo,
duration_min: parsedQuery.duration_min,
duration_max: parsedQuery.duration_max,
offset: currentPage * itemsPerPage,
Expand Down Expand Up @@ -107,6 +111,11 @@ function createAppState() {
everywhere = params['everywhere'] === 'true';
future = params['future'] !== 'false';

const from = parseInt(params['timestamp_from'], 10);
timestampFrom = !isNaN(from) ? from : undefined;
const to = parseInt(params['timestamp_to'], 10);
timestampTo = !isNaN(to) ? to : undefined;

const sBy = params['sortBy'];
if (sBy && isSortBy(sBy)) sortBy = sBy;
else sortBy = 'timestamp';
Expand Down Expand Up @@ -135,6 +144,8 @@ function createAppState() {
query,
everywhere,
future,
timestamp_from: timestampFrom,
timestamp_to: timestampTo,
sortBy,
sortOrder,
page: currentPage + 1
Expand Down Expand Up @@ -171,12 +182,14 @@ function createAppState() {
const cleanup = $effect.root(() => {
$effect(() => {
_search();
trackSearch({ query, everywhere, future, sortBy, sortOrder, itemsPerPage, page: currentPage + 1 });
trackSearch({ query, everywhere, future, timestampFrom, timestampTo, sortBy, sortOrder, itemsPerPage, page: currentPage + 1 });

updateUrlHash({
query: query || undefined,
everywhere: everywhere || undefined,
future: future ? undefined : 'false',
timestamp_from: timestampFrom,
timestamp_to: timestampTo,
sortBy: sortBy === 'timestamp' ? undefined : sortBy,
sortOrder: sortOrder === 'desc' ? undefined : sortOrder,
page: currentPage > 0 ? currentPage + 1 : undefined
Expand Down Expand Up @@ -219,6 +232,10 @@ function createAppState() {
set everywhere(value) { everywhere = value; currentPage = 0; },
get future() { return future; },
set future(value) { future = value; currentPage = 0; },
get timestampFrom() { return timestampFrom; },
set timestampFrom(value) { timestampFrom = value; currentPage = 0; },
get timestampTo() { return timestampTo; },
set timestampTo(value) { timestampTo = value; currentPage = 0; },
get sortBy() { return sortBy; },
get sortOrder() { return sortOrder; },
get currentPage() { return currentPage; },
Expand Down
2 changes: 2 additions & 0 deletions server/RSSFeedGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export class RSSFeedGenerator {
sortBy: urlQuery.sortBy ?? 'timestamp',
sortOrder: urlQuery.sortOrder ?? 'desc',
future,
timestamp_from: (typeof urlQuery.timestamp_from == 'string') ? parseInt(urlQuery.timestamp_from) : undefined,
timestamp_to: (typeof urlQuery.timestamp_to == 'string') ? parseInt(urlQuery.timestamp_to) : undefined,
duration_min: parsedQuery.duration_min,
duration_max: parsedQuery.duration_max,
offset: (typeof urlQuery.offset == 'string') ? parseInt(urlQuery.offset) : 0,
Expand Down
18 changes: 17 additions & 1 deletion server/SearchEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,23 @@ export class SearchEngine {
opensearchQuery.body.query.bool.filter.push(durationFilter);
}

if (query.future === false) {
const hasExplicitTimestampRange = query.timestamp_from != undefined || query.timestamp_to != undefined;
if (hasExplicitTimestampRange) {
const timestampFilter: { range: { timestamp: { gte?: number, lte?: number } } } = {
range: { timestamp: {} }
};

if (query.timestamp_from != undefined) {
timestampFilter.range.timestamp.gte = query.timestamp_from;
}

if (query.timestamp_to != undefined) {
timestampFilter.range.timestamp.lte = query.timestamp_to;
}
opensearchQuery.body.query.bool.filter.push(timestampFilter);
}

if (query.future === false && !hasExplicitTimestampRange) {
opensearchQuery.body.query.bool.filter.push({
range: {
timestamp: { to: 'now+1h/h' }
Expand Down