Skip to content

Commit

Permalink
Merge branch 'master' into fix_grouping
Browse files Browse the repository at this point in the history
  • Loading branch information
kgodey authored Jul 23, 2021
2 parents 2e57f46 + d0efbc0 commit 6fceca3
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 12 deletions.
3 changes: 2 additions & 1 deletion mathesar_ui/src/components/select/Select.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
<svelte:fragment slot="content">
<ul>
{#each options as option (option[idKey])}
<li class:selected={option === value} on:click={() => setValue(option)}>
<li class:selected={option[idKey] === value[idKey]}
on:click={() => setValue(option)}>
<span>{option[labelKey]}</span>
</li>
{/each}
Expand Down
10 changes: 9 additions & 1 deletion mathesar_ui/src/sections/table-view/TableView.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$display-opts-pane-width: 310px;
$display-opts-pane-width: 360px;

section.table-section .tab-container {
.tab-content-holder {
Expand Down Expand Up @@ -59,6 +59,14 @@ section.table-section .tab-container {
width: 178px;
}
}
td.filter-action {
text-align: right;
}
td.value {
.text-input {
background: #fff;
}
}

tr.add-option td {
padding-top: 10px;
Expand Down
8 changes: 7 additions & 1 deletion mathesar_ui/src/sections/table-view/TableView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,12 @@
<div class="actions-pane">
<Button appearance="plain" on:click={openDisplayOptions}>
<Icon data={faFilter} size="0.8em"/>
<span>Filters</span>
<span>
Filters
{#if $options.filter?.filters?.length > 0}
({$options.filter?.filters?.length})
{/if}
</span>
</Button>

<Button appearance="plain" on:click={openDisplayOptions}>
Expand Down Expand Up @@ -165,6 +170,7 @@
columns={$columns}
bind:sort={$options.sort}
bind:group={$options.group}
bind:filter={$options.filter}
on:reload={reload}
on:close={closeDisplayOptions}/>
{/if}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import type {
SortOption,
GroupOption,
FilterOption,
TableColumnData,
} from '@mathesar/stores/tableData';
import type { SelectOption } from '@mathesar-components/types';
import FilterSection from './FilterSection.svelte';
import SortSection from './SortSection.svelte';
import GroupSection from './GroupSection.svelte';
Expand All @@ -19,6 +21,7 @@
export let columns: TableColumnData;
export let sort: SortOption;
export let group: GroupOption;
export let filter: FilterOption;
function getColumnOptions(
_columns: TableColumnData,
Expand All @@ -41,13 +44,7 @@
</Button>
</div>

<FilterSection options={columnOptions} bind:filter on:reload/>
<SortSection options={columnOptions} bind:sort on:reload/>
<GroupSection options={columnOptions} bind:group on:reload/>

<section>
<div class="header">Filter</div>
<div class="content">
TODO
</div>
</section>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<script lang="ts">
import { createEventDispatcher, onMount, onDestroy } from 'svelte';
import {
faTimes,
} from '@fortawesome/free-solid-svg-icons';
import {
Icon,
Button,
Select,
TextInput,
} from '@mathesar-components';
import type {
FilterEntry,
} from '@mathesar/stores/tableData';
import type { SelectOption } from '@mathesar-components/types';
const dispatch = createEventDispatcher();
export let options: SelectOption[];
export let conditions: SelectOption[];
export let column: FilterEntry['column'];
export let condition: FilterEntry['condition'];
export let value: FilterEntry['value'];
let inputValue: string;
let timer;
onMount(() => {
inputValue = value;
});
onDestroy(() => {
clearTimeout(timer);
});
function onValueChange(_inputValue: string) {
clearTimeout(timer);
timer = setTimeout(() => {
if (value !== _inputValue) {
value = _inputValue;
dispatch('reload');
}
}, 500);
}
$: onValueChange(inputValue);
</script>

<tr>
<td class="column">
<Select {options} bind:value={column}
on:change={() => dispatch('reload')}/>
</td>
<td class="dir">
<Select options={conditions} bind:value={condition}
on:change={() => dispatch('reload')}/>
</td>
<td class="value">
<TextInput bind:value={inputValue}/>
</td>
<td>
<Button size="small" on:click={() => dispatch('removeFilter')}>
<Icon data={faTimes}/>
</Button>
</td>
</tr>
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte';
import {
faTimes,
faPlus,
} from '@fortawesome/free-solid-svg-icons';
import {
Icon,
Button,
Select,
TextInput,
} from '@mathesar-components';
import type {
FilterOption,
} from '@mathesar/stores/tableData';
import type { SelectOption } from '@mathesar-components/types';
import FilterEntry from './FilterEntry.svelte';
const dispatch = createEventDispatcher();
export let options: SelectOption[];
export let filter: FilterOption;
let filterCombination: SelectOption;
let filterColumn: SelectOption;
let filterCondition: SelectOption;
let filterValue = '';
let addNew = false;
const combinations = [
{ id: 'and', label: 'and' },
{ id: 'or', label: 'or' },
];
const conditions = [
{ id: 'eq', label: 'equals' },
{ id: 'ne', label: 'not equals' },
];
onMount(() => {
filterCombination = filter?.combination ?? combinations[0];
});
function addFilter() {
filter = {
combination: filterCombination || filter?.combination || combinations[0],
filters: [
...(filter?.filters || []),
{
column: filterColumn,
condition: filterCondition,
value: filterValue,
},
],
};
[filterColumn] = options;
[filterCondition] = conditions;
filterValue = '';
dispatch('reload');
addNew = false;
}
function removeFilter(index: number) {
filter?.filters?.splice(index, 1);
filter = { ...filter };
dispatch('reload');
}
function setFilterCombination() {
filter = {
...filter,
combination: filterCombination,
};
dispatch('reload');
}
</script>

<section>
<div class="header">
<span>
Filters
{#if filter?.filters?.length > 0}
({filter?.filters?.length})
{/if}
</span>
</div>
<div class="content">
<table>
{#if filter?.filters?.length > 0}
<tr>
<td>
<Select options={combinations} bind:value={filterCombination}
on:change={setFilterCombination}/>
</td>
</tr>
{/if}
{#each filter?.filters || [] as option, index (option)}
<FilterEntry {options} {conditions}
bind:column={option.column}
bind:condition={option.condition}
bind:value={option.value}
on:removeFilter={() => removeFilter(index)}
on:reload={() => dispatch('reload')}/>
{:else}
<tr>
<td class="empty-msg" colspan="3">
No filters added
</td>
</tr>
{/each}

{#if options.length > 0}
{#if !addNew}
<tr class="add-option">
<td colspan="3">
<Button on:click={() => { addNew = true; }}>
Add new filter
</Button>
</td>
</tr>

{:else}
<tr class="add-option">
<td class="column">
<Select {options} bind:value={filterColumn}/>
</td>
<td class="dir">
<Select options={conditions} bind:value={filterCondition}/>
</td>
<td class="value" colspan="2">
<TextInput bind:value={filterValue}/>
</td>
</tr>
<tr>
<td class="filter-action" colspan="4">
<Button size="small" on:click={addFilter}>
<Icon data={faPlus}/>
</Button>
<Button size="small" on:click={() => { addNew = false; }}>
<Icon data={faTimes}/>
</Button>
</td>
</tr>
{/if}
{/if}
</table>
</div>
</section>
30 changes: 29 additions & 1 deletion mathesar_ui/src/stores/tableData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { get, writable, Writable } from 'svelte/store';
import { getAPI, States } from '@mathesar/utils/api';
import type { CancellablePromise } from '@mathesar/components';
import type { SelectOption } from '@mathesar-components/types';

export const DEFAULT_COUNT_COL_WIDTH = 70;
export const DEFAULT_COLUMN_WIDTH = 160;
Expand Down Expand Up @@ -54,11 +55,24 @@ interface TableRecordData {

export type SortOption = Map<string, 'asc' | 'desc'>;
export type GroupOption = Set<string>;

export type StringCondition = 'eq' | 'ne' | 'ilike' | 'not_ilike';
export interface FilterEntry {
column: SelectOption,
condition: SelectOption,
value: string
}
export interface FilterOption {
combination: SelectOption,
filters: FilterEntry[]
}

export interface TableOptionsData {
limit: number,
offset: number,
sort: SortOption,
group: GroupOption
group: GroupOption,
filter: FilterOption
}

export type ColumnPosition = Map<string, {
Expand Down Expand Up @@ -339,6 +353,19 @@ export async function fetchTableRecords(
`group_count_by=${encodeURIComponent(JSON.stringify(groupOptions))}`,
);
}
if (optionData.filter?.filters?.length > 0) {
const filter = {};
const terms = optionData.filter?.filters.map((term) => ({
field: term.column.id,
op: term.condition.id,
value: term.value,
}));
filter[optionData.filter.combination.id as string] = terms;
params.push(
`filters=${encodeURIComponent(JSON.stringify(filter))}`,
);
}

const tableRecordsPromise = getAPI<TableRecordsResponse>(`/tables/${id}/records/?${params.join('&')}`);

if (!table.config.previousRecordRequestSet) {
Expand Down Expand Up @@ -443,6 +470,7 @@ export function getTable(db: string, id: number, options?: Partial<TableOptionsD
offset: options?.offset || 0,
sort: options?.sort || null,
group: options?.group || null,
filter: options?.filter || null,
}),
display: {
horizontalScrollOffset: writable(0),
Expand Down
Loading

0 comments on commit 6fceca3

Please sign in to comment.