Skip to content

Commit

Permalink
ensure filters are synced to URL in all reports
Browse files Browse the repository at this point in the history
  • Loading branch information
yagebu committed Dec 28, 2024
1 parent 958c795 commit a3ee14d
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 95 deletions.
13 changes: 9 additions & 4 deletions frontend/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { get as store_get } from "svelte/store";

import type { Entry } from "../entries";
import { urlFor } from "../helpers";
import { urlForRaw } from "../helpers";
import { fetchJSON } from "../lib/fetch";
import type { ValidationT } from "../lib/validation";
import { string } from "../lib/validation";
Expand Down Expand Up @@ -45,7 +47,8 @@ export async function put<T extends keyof PutAPIInputs>(
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
};
const url = urlFor(`api/${endpoint}`);
const $urlForRaw = store_get(urlForRaw);
const url = $urlForRaw(`api/${endpoint}`);
const json = await fetchJSON(url, { method: "PUT", ...opts });
const res = string(json);
if (res.is_ok) {
Expand Down Expand Up @@ -88,7 +91,8 @@ export async function get<T extends keyof GetAPIParams>(
? [undefined?, number?]
: [GetAPIParams[T], number?]
): Promise<ValidationT<GetAPIValidators[T]>> {
const url = urlFor(`api/${endpoint}`, params, false);
const $urlForRaw = store_get(urlForRaw);
const url = $urlForRaw(`api/${endpoint}`, params);
const json = await fetchJSON(url);
const res = getAPIValidators[endpoint](json);
if (res.is_ok) {
Expand All @@ -112,7 +116,8 @@ export async function doDelete<T extends keyof DeleteAPIParams>(
endpoint: T,
params: DeleteAPIParams[T],
): Promise<string> {
const url = urlFor(`api/${endpoint}`, params, false);
const $urlForRaw = store_get(urlForRaw);
const url = $urlForRaw(`api/${endpoint}`, params);
const json = await fetchJSON(url, { method: "DELETE" });
const res = string(json);
if (res.is_ok) {
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { get as store_get } from "svelte/store";

import { getUrlPath, urlFor } from "./helpers";
import { getUrlPath, urlForRaw } from "./helpers";
import { fetch } from "./lib/fetch";
import { log_error } from "./log";
import { extensions } from "./stores";
Expand All @@ -22,7 +22,8 @@ export class ExtensionApi {
body?: unknown,
output: "json" | "string" | "raw" = "json",
): Promise<unknown> {
const url = urlFor(`extension/${this.name}/${endpoint}`, params, false);
const $urlForRaw = store_get(urlForRaw);
const url = $urlForRaw(`extension/${this.name}/${endpoint}`, params);
let opts = {};
if (body != null) {
opts =
Expand Down Expand Up @@ -109,7 +110,8 @@ class ExtensionData {
}

async function loadExtensionModule(name: string): Promise<ExtensionData> {
const url = urlFor(`extension_js_module/${name}.js`, undefined, false);
const $urlForRaw = store_get(urlForRaw);
const url = $urlForRaw(`extension_js_module/${name}.js`, undefined);
const mod = await (import(url) as Promise<{ default?: ExtensionModule }>);
if (typeof mod.default === "object") {
return new ExtensionData(mod.default, { api: new ExtensionApi(name) });
Expand Down
73 changes: 44 additions & 29 deletions frontend/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { derived, get as store_get } from "svelte/store";

import { base_url, fava_options } from "./stores";
import { searchParams, urlSyncedParams } from "./stores/url";
import { syncedSearchParams } from "./stores/url";

/**
* Get the URL path relative to the base url of the current ledger.
Expand All @@ -26,23 +26,17 @@ export function getUrlPath(
*/
export function urlForInternal(
$base_url: string,
$searchParams: URLSearchParams | null,
$syncedSearchParams: URLSearchParams | null,
report: string,
params: Record<string, string | number | undefined> | undefined,
): string {
const url = `${$base_url}${report}`;
const urlParams = new URLSearchParams();
if ($searchParams) {
for (const name of urlSyncedParams) {
const value = $searchParams.get(name);
if (value != null) {
urlParams.set(name, value);
}
}
}
const urlParams = $syncedSearchParams
? new URLSearchParams($syncedSearchParams)
: new URLSearchParams();
if (params) {
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined) {
if (value != null) {
urlParams.set(key, value.toString());
}
});
Expand All @@ -54,27 +48,48 @@ export function urlForInternal(
/**
* Get the URL string for one of Fava's reports.
*/
export function urlFor(
report: string,
params?: Record<string, string | number | undefined>,
update = true,
): string {
const $base_url = store_get(base_url);
const $searchParams = update ? store_get(searchParams) : null;
return urlForInternal($base_url, $searchParams, report, params);
}
export const urlFor = derived(
[base_url, syncedSearchParams],
([$base_url, $syncedSearchParams]) =>
(
report: string,
params?: Record<string, string | number | undefined>,
): string =>
urlForInternal($base_url, $syncedSearchParams, report, params),
);

/**
* Get the URL string for one of Fava's reports - without synced params.
*/
export const urlForRaw = derived(
[base_url],
([$base_url]) =>
(
report: string,
params?: Record<string, string | number | undefined>,
): string =>
urlForInternal($base_url, null, report, params),
);

const use_external_editor = derived(
fava_options,
($fava_options) => $fava_options.use_external_editor,
);

/** URL for the editor to the source location of an entry. */
export function urlForSource(file_path: string, line: string): string {
return store_get(fava_options).use_external_editor
? `beancount://${file_path}?lineno=${line}`
: urlFor("editor/", { file_path, line });
}
export const urlForSource = derived(
[urlFor, use_external_editor],
([$urlFor, $use_external_editor]) =>
(file_path: string, line: string): string =>
$use_external_editor
? `beancount://${file_path}?lineno=${line}`
: $urlFor("editor/", { file_path, line }),
);

/** URL for the account report (derived store to keep track of filter changes.). */
export const urlForAccount = derived(
[base_url, searchParams],
([$base_url, $searchParams]) =>
urlFor,
($urlFor) =>
(account: string, params?: Record<string, string>): string =>
urlForInternal($base_url, $searchParams, `account/${account}/`, params),
$urlFor(`account/${account}/`, params),
);
2 changes: 1 addition & 1 deletion frontend/src/modals/EntryContext.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
{_("Location")}:
<code>
<a
href={urlForSource(
href={$urlForSource(
entry.meta.filename?.toString() ?? "",
entry.meta.lineno?.toString() ?? "",
)}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/modals/Export.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{#if shown}
<div>
<h3>{_("Export")}:</h3>
<a href={urlFor("download-journal")} data-remote>
<a href={$urlFor("download-journal")} data-remote>
{_("Download currently filtered entries as a Beancount file")}
</a>
</div>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/reports/documents/DocumentPreview.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@

<script lang="ts">
import DocumentPreviewEditor from "../../editor/DocumentPreviewEditor.svelte";
import { urlForRaw } from "../../helpers";
import { ext } from "../../lib/paths";
import { base_url } from "../../stores";
export let filename: string;
$: extension = ext(filename).toLowerCase();
$: url = `${$base_url}document/?filename=${encodeURIComponent(filename)}`;
$: url = $urlForRaw("document/", { filename });
</script>

{#if extension === "pdf"}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/reports/editor/EditorMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
let insertEntryOptions = $derived($fava_options.insert_entry);
function goToFileAndLine(filename: string, line?: number) {
const url = urlFor("editor/", { file_path: filename, line });
const url = $urlFor("editor/", { file_path: filename, line });
// only load if the file changed.
const load = filename !== file_path;
router.navigate(url, load);
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/reports/errors/Errors.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
{#each sorted_errors as { message, source }}
<tr>
{#if source}
{@const url = urlForSource(
{@const url = $urlForSource(
source.filename,
source.lineno.toString(),
)}
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/reports/holdings/Holdings.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
{#if aggregation_key === "all"}
{_("Holdings")}
{:else}
<a href={urlFor("holdings/")}>{_("Holdings")}</a>
<a href={$urlFor("holdings/")}>{_("Holdings")}</a>
{/if}
</h3>
<h3>
{#if aggregation_key === "by_account"}
{_("Holdings by")} {_("Account")}
{:else}
<a href={urlFor("holdings/by_account/")}>
<a href={$urlFor("holdings/by_account/")}>
{_("Holdings by")}
{_("Account")}
</a>
Expand All @@ -33,7 +33,7 @@
{#if aggregation_key === "by_currency"}
{_("Holdings by")} {_("Currency")}
{:else}
<a href={urlFor("holdings/by_currency/")}>
<a href={$urlFor("holdings/by_currency/")}>
{_("Holdings by")}
{_("Currency")}
</a>
Expand All @@ -43,7 +43,7 @@
{#if aggregation_key === "by_cost_currency"}
{_("Holdings by")} {_("Cost currency")}
{:else}
<a href={urlFor("holdings/by_cost_currency/")}>
<a href={$urlFor("holdings/by_cost_currency/")}>
{_("Holdings by")}
{_("Cost currency")}
</a>
Expand All @@ -52,7 +52,7 @@
</div>

<p>
<a href={urlFor("query", { query_string })}>{_("Query")}</a>
<a href={$urlFor("query", { query_string })}>{_("Query")}</a>
<QueryLinks query={query_string} />
</p>
<QueryTable table={query_result_table} filter_empty="units" />
2 changes: 1 addition & 1 deletion frontend/src/reports/import/Import.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@

{#if $fava_options.import_config == null}
<p>
No importers configured. See <a href={urlFor("help/import")}
No importers configured. See <a href={$urlFor("help/import")}
>Help (Import)</a
> for more information.
</p>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/reports/options/Options.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<h2>
{_("Fava options")}
<a href={urlFor("help/options")}>({_("help")})</a>
<a href={$urlFor("help/options")}>({_("help")})</a>
</h2>
<OptionsTable options={fava_options} />

Expand Down
28 changes: 15 additions & 13 deletions frontend/src/reports/query/QueryLinks.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,29 @@
import { _ } from "../../i18n";
import { HAVE_EXCEL } from "../../stores";
/** The query string. */
export let query: string;
/**
* URL to download a query.
*/
function queryUrl(query_string: string, format: string) {
return urlFor(`download-query/query_result.${format}`, {
query_string,
});
interface Props {
/** The query string. */
query: string;
}
let { query }: Props = $props();
let params = $derived({ query_string: query });
</script>

<span>
({_("Download as")}
<a href={queryUrl(query, "csv")} data-remote>CSV</a>
<a href={$urlFor("download-query/query_result.csv", params)} data-remote>
CSV
</a>
{#if $HAVE_EXCEL}
,
<a href={queryUrl(query, "xlsx")} data-remote>XLSX</a>
<a href={$urlFor("download-query/query_result.xlsx", params)} data-remote>
XLSX
</a>
, or
<a href={queryUrl(query, "ods")} data-remote>ODS</a>
<a href={$urlFor("download-query/query_result.ods", params)} data-remote>
ODS
</a>
{/if}
)
</span>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/sidebar/AsideContents.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<ul class="submenu">
{#each user_queries as { query_string, name }}
<li>
<a href={urlFor("query/", { query_string })}>{truncate(name)}</a>
<a href={$urlFor("query/", { query_string })}>{truncate(name)}</a>
</li>
{/each}
</ul>
Expand Down
8 changes: 3 additions & 5 deletions frontend/src/sidebar/SidebarLink.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script lang="ts">
import type { Snippet } from "svelte";
import { urlFor } from "../helpers";
import type { KeySpec } from "../keyboard-shortcuts";
import { keyboardShortcut } from "../keyboard-shortcuts";
import { base_url } from "../stores";
import { pathname, synced_query_string } from "../stores/url";
import { pathname } from "../stores/url";
interface Props {
report: string;
Expand All @@ -17,9 +17,7 @@
let { report, name, key, remote, bubble, children }: Props = $props();
let href = $derived(
remote ? report : `${$base_url}${report}/${$synced_query_string}`,
);
let href = $derived(remote ? report : $urlFor(`${report}/`));
let selected = $derived(remote ? false : href.includes($pathname));
</script>

Expand Down
Loading

0 comments on commit a3ee14d

Please sign in to comment.