Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LWS-274: labels for Supersearch #1186

Merged
merged 23 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b6118d8
Update codemirror after navigate to apply filters
jesperengstrom Dec 9, 2024
0bfecb3
Migrate search.svelte, add callback fn to Lxlqualifier
jesperengstrom Dec 9, 2024
523709b
add supersearch package:watch
jesperengstrom Dec 9, 2024
f19ae0d
Update response from server side with needed mapping stuff
jesperengstrom Dec 9, 2024
2fc0734
Refactor lxlQualifier extension, add qualifier component, styling
jesperengstrom Dec 9, 2024
c5e1691
Make supersearch routes not crash
jesperengstrom Dec 9, 2024
f11ccd8
Fix
jesperengstrom Dec 9, 2024
3259511
Fix test
jesperengstrom Dec 10, 2024
9f96eef
Accomplish url sync with $effect, not afterNavigate
jesperengstrom Dec 11, 2024
a35bf94
Fix all labels disappearing efter entering invalid qualifier
jesperengstrom Dec 11, 2024
8c0a017
Dispatch StateEffect when new data is loaded
jesperengstrom Dec 12, 2024
2a72d8a
Extend language highlighter, reduce getQualifiers
jesperengstrom Dec 12, 2024
56f6faf
CSS fix
jesperengstrom Dec 12, 2024
28a5d07
Invalid underline fix
jesperengstrom Dec 12, 2024
62a6380
Update readme
jesperengstrom Dec 17, 2024
d1b8c45
Add tests
jesperengstrom Dec 17, 2024
506953c
Test fix
jesperengstrom Dec 17, 2024
7f28c08
Remove package:watch (add in another PR)
jesperengstrom Dec 17, 2024
15b1e43
Remove comment
jesperengstrom Dec 17, 2024
061012a
Export messages constant
jesperengstrom Dec 17, 2024
aecdeb1
Derive lxlQualifier plugin
jesperengstrom Dec 17, 2024
a3f9e91
Put back call to getQualifiers on update
jesperengstrom Dec 18, 2024
c4eef3b
Save prev data id to prevent double effects
jesperengstrom Dec 18, 2024
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
75 changes: 50 additions & 25 deletions lxl-web/src/lib/components/Search.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,29 @@
import { SuperSearch, lxlQualifierPlugin } from 'supersearch';
import addDefaultSearchParams from '$lib/utils/addDefaultSearchParams';
import getSortedSearchParams from '$lib/utils/getSortedSearchParams';
import getLabelFromMappings from '$lib/utils/getLabelsFromMapping.svelte';
import type { DisplayMapping } from '$lib/types/search';
import BiSearch from '~icons/bi/search';
import { lxlQuery } from 'codemirror-lang-lxlquery';
import '$lib/styles/lxlquery.css';

export let placeholder: string;
export let autofocus: boolean = false;
interface Props {
placeholder: string;
autofocus?: boolean;
}

let { placeholder, autofocus = false }: Props = $props();

const useSuperSearch = env?.PUBLIC_USE_SUPERSEARCH === 'true';
const showAdvanced = $page.url.searchParams.get('_x') === 'advanced' || useSuperSearch;

$: showAdvanced = $page.url.searchParams.get('_x') === 'advanced';
let q = $page.params.fnurgel
? '' //don't reflect related search on resource pages
: showAdvanced
? $page.url.searchParams.get('_q')?.trim() || ''
: $page.url.searchParams.get('_i')?.trim() || '';
let q = $state(
$page.params.fnurgel
? '' //don't reflect related search on resource pages
: showAdvanced
? $page.url.searchParams.get('_q')?.trim() || ''
: $page.url.searchParams.get('_i')?.trim() || ''
);

let params = getSortedSearchParams(addDefaultSearchParams($page.url.searchParams));
// Always reset these params on new search
Expand All @@ -27,10 +37,12 @@
params.delete('_p');
const searchParams = Array.from(params);

let suggestMapping: DisplayMapping[] | undefined = $state();

afterNavigate(({ to }) => {
/** Update input value after navigation on /find route */
if (to?.url) {
let param = showAdvanced ? '_q' : '_i';
let param = $page.url.searchParams.get('_x') === 'advanced' || useSuperSearch ? '_q' : '_i';
q = $page.params.fnurgel ? '' : new URL(to.url).searchParams.get(param)?.trim() || '';
}
});
Expand All @@ -54,10 +66,23 @@
}
return undefined;
}

function handleTransform(data) {
suggestMapping = data?.mapping;
return data;
}

let derivedLxlQualifierPlugin = $derived.by(() => {
function getLabels(key: string, value?: string) {
let pageMapping = $page.data.searchResult?.mapping;
return getLabelFromMappings(key, value, pageMapping, suggestMapping);
}
return lxlQualifierPlugin(getLabels);
});
</script>

<form class="relative w-full" action="find" on:submit={handleSubmit}>
{#if env?.PUBLIC_USE_SUPERSEARCH === 'true'}
<form class="relative w-full" action="find" onsubmit={handleSubmit}>
{#if useSuperSearch}
<SuperSearch
name="_q"
bind:value={q}
Expand All @@ -71,8 +96,9 @@
cursor: cursor.toString()
});
}}
transformFn={handleTransform}
paginationQueryFn={handlePaginationQuery}
extensions={[lxlQualifierPlugin]}
extensions={[derivedLxlQualifierPlugin]}
>
{#snippet resultItem(item)}
<button type="button">
Expand All @@ -81,7 +107,7 @@
{/snippet}
</SuperSearch>
{:else}
<!-- svelte-ignore a11y-autofocus -->
<!-- svelte-ignore a11y_autofocus -->
<input
id="main-search"
class="h-12 w-full rounded-full pr-12 text-secondary shadow-accent-dark/32 focus:shadow-search-focus focus:outline
Expand All @@ -96,24 +122,23 @@
{autofocus}
data-testid="main-search"
/>
{#each searchParams as [name, value]}
{#if name !== '_q'}
<input type="hidden" {name} {value} />
{/if}
{/each}

<input type="hidden" name="_i" value={q} />
{#if $page.url.searchParams.get('_x') === 'advanced'}
<!-- keep 'edit' state on new search -->
<input type="hidden" name="_x" value="advanced" />
{/if}

<button
type="submit"
class="button-primary absolute right-1 top-1 rounded-full px-3 sm:right-2 sm:top-2 sm:px-4"
>
<BiSearch fill="currentColor" aria-hidden="true" />
<span class="sr-only sm:not-sr-only">{$page.data.t('search.search')}</span>
</button>
<input type="hidden" name="_i" value={q} />
{#if $page.url.searchParams.get('_x') === 'advanced'}
<!-- keep 'edit' state on new search -->
<input type="hidden" name="_x" value="advanced" />
{/if}
{/if}
<!-- params used by all search modes -->
{#each searchParams as [name, value]}
{#if name !== '_q'}
<input type="hidden" {name} {value} />
{/if}
{/each}
</form>
44 changes: 37 additions & 7 deletions lxl-web/src/lib/styles/lxlquery.css
Original file line number Diff line number Diff line change
@@ -1,17 +1,47 @@
.lxl-qualifier,
.lxl-qualifier-remove {
background: rgba(14, 113, 128, 0.15);
padding: 2px 5px;
.lxl-qualifier {
display: inline-flex;
color: rgb(0, 128, 0);
background: rgba(14, 113, 128, 0.1);
padding-top: 3px;
padding-bottom: 3px;
}

.lxl-qualifier-key {
color: green;
padding-left: 5px;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}

.lxl-qualifier-value,
.lxl-qualifier-remove {
padding-right: 5px;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}

.lxl-qualifier-remove,
.lxl-qualifier-value.atomic {
padding-left: 5px;
}

.lxl-qualifier-value:has(~ .lxl-qualifier-remove) {
border-radius: 0;
}

.invalid > .lxl-qualifier-key {
text-decoration: underline 2px solid;
text-decoration-color: rgba(255, 0, 0, 0.326);
}

.atomic {
background: rgba(14, 113, 128, 0.2);
user-select: none;
}

.lxl-boolean-query {
color: purple;
color: rgb(128, 0, 128);
}

.lxl-wildcard {
color: purple;
color: rgb(128, 0, 128);
}
2 changes: 2 additions & 0 deletions lxl-web/src/lib/types/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,12 @@ interface SpellingSuggestion {
export interface DisplayMapping {
'@id'?: string;
display?: DisplayDecorated;
displayStr?: string;
up?: Link;
children?: DisplayMapping[];
label?: string;
operator: keyof typeof SearchOperators;
property?: string;
}

export interface PartialCollectionView {
Expand Down
62 changes: 62 additions & 0 deletions lxl-web/src/lib/utils/getLabelsFromMapping.svelte.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import type { DisplayMapping } from '$lib/types/search';

let prevSuggestMapping: DisplayMapping[] | undefined;

function getLabelFromMappings(
key: string,
value?: string,
pageMapping?: DisplayMapping[],
suggestMapping?: DisplayMapping[]
) {
const pageLabels = iterateMapping(key, value, pageMapping);
const suggestLabels = iterateMapping(key, value, suggestMapping || prevSuggestMapping);

const keyLabel = suggestLabels.keyLabel || pageLabels.keyLabel;
const valueLabel = suggestLabels.valueLabel || pageLabels.valueLabel;
// only page data have 'up' links we can use
const removeLink = pageLabels.keyLabel ? pageLabels.removeLink : undefined;

if (suggestMapping) {
// TODO remove when invalid qualifier no longer result in empty error response
// until when we need to save latest 'successful' suggest mapping
prevSuggestMapping = suggestMapping;
}

return { keyLabel, valueLabel, removeLink };
}

function iterateMapping(
key: string,
value: string | undefined,
mapping: DisplayMapping[] | undefined | null
) {
let keyLabel: string | undefined;
let valueLabel: string | undefined;
let removeLink: string | undefined;

if (mapping && Array.isArray(mapping)) {
_iterate(mapping);

function _iterate(m: DisplayMapping[]) {
m.forEach((el) => {
if (el.children) {
_iterate(el.children);
} else if (el.property === key) {
keyLabel = el.label;
const isLinked = !!el.display?.['@id'];
if (isLinked) {
if (el.displayStr) {
// only use atomic ranges for linked values
valueLabel = el.displayStr;
}
// only show remove btn for pills that can't be edited
removeLink = el.up?.['@id'];
}
}
});
}
}
return { keyLabel, valueLabel, removeLink };
}

export default getLabelFromMappings;
Loading
Loading