Skip to content

Commit

Permalink
[ALS-6161 + ALS-6162] Search, Filters, Exports
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesPeck committed Apr 15, 2024
1 parent 35c9f4e commit ae1ca5e
Show file tree
Hide file tree
Showing 40 changed files with 2,014 additions and 387 deletions.
16 changes: 8 additions & 8 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: "weekly"
interval: 'weekly'
commit-message:
prefix: "[npm] "
prefix: '[npm] '

- package-ecosystem: "docker"
directory: "/"
- package-ecosystem: 'docker'
directory: '/'
schedule:
interval: "weekly"
interval: 'weekly'
commit-message:
prefix: "[docker] "
prefix: '[docker] '
13 changes: 8 additions & 5 deletions src/app.postcss
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ body {
@apply h-full overflow-hidden;
}

#shell-header,
section.main-content {
padding: 0 1em;
}
Expand All @@ -31,6 +30,10 @@ section.main-content.w-full {
}
}

input[type='checkbox'] {
@apply checkbox;
}

@media print {
.app-bar #page-navigation {
display: none;
Expand Down Expand Up @@ -203,17 +206,17 @@ nav#page-navigation li a {
@apply rounded-container-token;
}
nav#page-navigation a[aria-current='page'] {
@apply variant-filled-secondary;
background-color: rgba(var(--color-primary-50-900));
color: rgb(var(--theme-font-color-base));
}
nav#page-navigation a:hover,
nav#page-navigation a:active {
@apply variant-filled-primary;
}

#landing input[type='search'] {
input[type='search'] {
width: 100%;
box-sizing: border-box;
margin-right: 0.5rem;
@apply input;
}

Expand Down Expand Up @@ -269,4 +272,4 @@ nav#page-navigation a:active {
height: 6rem;
margin-bottom: 1rem;
@apply rounded-container-token;
}
}
17 changes: 17 additions & 0 deletions src/lib/components/ModalWrapper.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script lang="ts">
import { getModalStore } from '@skeletonlabs/skeleton';
const modalStore = getModalStore();
</script>

{#if $modalStore[0]}
<div class="card p-4 w-modal shadow-xl space-y-4">
<header data-testid="modal-wrapper-header" class="text-2xl font-bold">
{$modalStore[0].title ?? '(title missing)'}
<button class="float-right" on:click={() => modalStore.close()}>&times;</button>
</header>
<svelte:component
this={$modalStore[0].meta.component}
existingFilter={$modalStore[0].meta.existingFilter}
/>
</div>
{/if}
183 changes: 183 additions & 0 deletions src/lib/components/OptionsSelectionList.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<script lang="ts">
import { quintOut } from 'svelte/easing';
import { crossfade } from 'svelte/transition';
import { flip } from 'svelte/animate';
const [send, receive] = crossfade({
fallback(node) {
const style = getComputedStyle(node);
const transform = style.transform === 'none' ? '' : style.transform;
return {
easing: quintOut,
css: (t) => `
transform: ${transform} scale(${t});
opacity: ${t}
`,
};
},
});
export let options: string[] = [];
export let allOptions: string[] = options;
export let selectedOptions: string[] = [];
export let showSelectAll: boolean = true;
export let loadMore: (searchTerm: string) => Promise<string[]>;
let searchInput: string = '';
let selectedOptionEndLocation = 20;
let optionsContainer: HTMLElement;
let selelectedOptionsContainer: HTMLElement;
async function handleScroll() {
if (!optionsContainer) return;
if (loadMore === undefined) return; //todo test this
if (shouldLoadMore(optionsContainer)) {
let nextOptions = await loadMore(searchInput);
if (nextOptions && Array.isArray(nextOptions) && nextOptions.length > 0) {
options = [...options, ...nextOptions];
}
}
}
function onSelect(option: string) {
options = options.filter((o) => o !== option);
selectedOptions = [...selectedOptions, option];
if (elementHasScrollbar(optionsContainer)) {
handleScroll();
}
}
function onUnselect(option: string) {
selectedOptions = selectedOptions.filter((o) => o !== option);
options = [option, ...options];
}
function elementHasScrollbar(element: HTMLElement) {
return element.scrollHeight > element.clientHeight;
}
function loadMoreSelectedOptions() {
if (!selelectedOptionsContainer) return;
if (shouldLoadMore(selelectedOptionsContainer)) {
selectedOptionEndLocation = selectedOptionEndLocation + 20;
}
}
function shouldLoadMore(element: HTMLElement) {
const scrollTop = element.scrollTop;
const containerHeight = element.clientHeight;
const contentHeight = element.scrollHeight;
const scrollBuffer = 30;
return (contentHeight - (scrollTop + containerHeight) <= scrollBuffer);
}
$: filteredOptions = options?.filter((option) =>
option.toLowerCase().includes(searchInput.toLowerCase()),
);
$: displayedSelectedOptions = selectedOptions.slice(0, selectedOptionEndLocation);
</script>

<div data-testid="optional-selection-list" class="flex w-full">
<div class="flex flex-1 flex-col h-full p-3 m-1 card">
<header class="flex pb-1">
<input
class="input"
type="search"
name="search"
bind:value={searchInput}
placeholder="Search..."
/>
{#if showSelectAll}
<button
id="select-all"
class="btn variant-ringed-surface hover:variant-filled-primary ml-2"
on:click={() => {
selectedOptions = allOptions;
selectedOptionEndLocation = 20;
options = [];
}}>Select All</button
>
{/if}
</header>
<section class="card-body">
<div
id="options-container"
bind:this={optionsContainer}
class="overflow-scroll scrollbar-color h-25vh"
on:scroll={() => handleScroll()}
>
{#each filteredOptions as option (option)}
<label
id="option-{option}"
class="p-1 m-1 cursor-pointer hover:variant-soft-surface hover:rounded-md"
in:receive={{ key: option }}
out:send={{ key: option }}
role="listitem"
animate:flip
>
<input
type="checkbox"
value={option}
on:click|preventDefault={() => onSelect(option)}
/>
{option}
</label>
{/each}
</div>
</section>
</div>
<div class="flex flex-1 flex-col h-full p-3 m-1 card">
<header class="flex justify-between pb-1">
<h5>Selected:</h5>
<button
id="clear"
class="btn variant-ringed-surface hover:variant-filled-primary ml-2"
on:click={() => {
selectedOptionEndLocation = 20;
displayedSelectedOptions.forEach((option) => onUnselect(option));
selectedOptions = [];
}}
disabled={selectedOptions.length === 0}>Clear</button
>
</header>
<section class="card-body">
<!-- on:scroll={() => selectedOptionsScolling} -->
<div
id="selected-options-container"
bind:this={selelectedOptionsContainer}
class="overflow-scroll scrollbar-color h-25vh"
on:scroll={() => loadMoreSelectedOptions()}
>
{#each displayedSelectedOptions as option (option)}
<label
id="option-{option}"
class="p-1 m-1 hover:variant-soft-surface hover:rounded-md cursor-pointer"
in:receive={{ key: option }}
out:send={{ key: option }}
animate:flip
role="listitem"
>
<input
type="checkbox"
class="mr-1"
value={option}
on:click|preventDefault={() => onUnselect(option)}
checked
/>
{option}
</label>
{/each}
</div>
</section>
</div>
</div>

<style>
.scrollbar-color {
scrollbar-color: rgba(var(--color-surface-300)) rgb(var(--color-surface-100));
}
.h-25vh {
height: 25vh;
}
</style>
44 changes: 44 additions & 0 deletions src/lib/components/Searchbox.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<script lang="ts">
export let placeholder = 'Search...';
export let search: () => void = () => {};
export let searchTerm = '';
</script>

<div class="flex w-full">
<input
type="search"
autocomplete="off"
class="search-box w-full"
data-testid="search-box"
aria-label="Type search terms here, use enter or the search button to submit search"
title="Type search terms here, use enter or the search button to submit search"
{placeholder}
bind:value={searchTerm}
on:keydown={(e) => e.key === 'Enter' && search()}
required
/>
<button
id="search-button"
class="btn variant-filled-primary search-button"
aria-label="Search"
title="Search"
disabled={!searchTerm}
on:click={search}
>
<i class="fas fa-search"></i>
</button>
</div>

<style>
.search-box {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
margin-right: 0% !important;
}
.search-button {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
padding-right: 1rem;
padding-left: 0.75rem;
}
</style>
6 changes: 2 additions & 4 deletions src/lib/components/UserToken.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
message:
'An error occured while parsing your token. Please try again later. If this problem persists, please contact an administrator.',
background: 'variant-filled-error',
hoverable: true,
});
return 0; //TODO: Handle errors
}
Expand Down Expand Up @@ -101,10 +102,7 @@
</div>
</section>
<footer class="card-footer">
<CopyButton
buttonText="Copy"
itemToCopy={$user.token || ''}
/>
<CopyButton buttonText="Copy" itemToCopy={$user.token || ''} />
<button
id="refresh-button"
class="btn variant-ringed-primary"
Expand Down
48 changes: 48 additions & 0 deletions src/lib/components/datatable/Row.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script lang="ts">
import type { Column } from '$lib/models/Tables';
import type { Indexable } from '$lib/types';
import Search from '$lib/stores/Search';
let { activeRow, expandableComponents, activeComponent } = Search;
export let cellOverides: Indexable = {};
export let columns: Column[] = [];
export let index: number = -2;
export let row: Indexable = {};
export let rowClickHandler: (index: number) => void;
function onClick(index: number) {
if (!index || index === -1) return;
rowClickHandler && rowClickHandler(index);
}
</script>

<tr id={index.toString()} on:click|stopPropagation={() => onClick(index)} class="cursor-pointer">
{#each columns as column}
<td>
{#if cellOverides[column.dataElement]}
<svelte:component
this={cellOverides[column.dataElement]}
data={{ index, row, cell: row[column.dataElement] }}
/>
{:else}
{row[column.dataElement]}
{/if}
</td>
{/each}
</tr>

{#if Object.keys($expandableComponents).length > 0 && $activeRow === index}
<tr class="expandable-row">
<td colspan={columns.length}>
{#if $activeComponent}
<svelte:component this={$activeComponent} data={row} />
{/if}
</td>
</tr>
{/if}

<style>
.expandable-row {
background-color: rgb(var(--color-surface-300)) !important;
}
</style>
Loading

0 comments on commit ae1ca5e

Please sign in to comment.