@gradio/dataframe 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/Dataframe.test.ts +697 -32
- package/Index.svelte +107 -106
- package/dist/Index.svelte +107 -106
- package/dist/Index.svelte.d.ts +0 -1
- package/dist/shared/BooleanCell.svelte +12 -6
- package/dist/shared/BooleanCell.svelte.d.ts +4 -18
- package/dist/shared/CellMenu.svelte +74 -49
- package/dist/shared/CellMenu.svelte.d.ts +5 -19
- package/dist/shared/CellMenuButton.svelte +3 -3
- package/dist/shared/CellMenuButton.svelte.d.ts +4 -18
- package/dist/shared/CellMenuIcons.svelte +1 -1
- package/dist/shared/CellMenuIcons.svelte.d.ts +4 -18
- package/dist/shared/DataCell.svelte +189 -0
- package/dist/shared/DataCell.svelte.d.ts +44 -0
- package/dist/shared/EditableCell.svelte +88 -64
- package/dist/shared/EditableCell.svelte.d.ts +8 -26
- package/dist/shared/EmptyRowButton.svelte +2 -2
- package/dist/shared/EmptyRowButton.svelte.d.ts +4 -18
- package/dist/shared/FilterMenu.svelte +26 -18
- package/dist/shared/FilterMenu.svelte.d.ts +5 -21
- package/dist/shared/HeaderCell.svelte +218 -0
- package/dist/shared/HeaderCell.svelte.d.ts +30 -0
- package/dist/shared/RowNumber.svelte +4 -2
- package/dist/shared/RowNumber.svelte.d.ts +4 -18
- package/dist/shared/Table.svelte +1037 -949
- package/dist/shared/Table.svelte.d.ts +12 -30
- package/dist/shared/Toolbar.svelte +32 -22
- package/dist/shared/Toolbar.svelte.d.ts +6 -21
- package/dist/shared/column_measurement.svelte.d.ts +20 -0
- package/dist/shared/column_measurement.svelte.js +79 -0
- package/dist/shared/icons/FilterIcon.svelte +14 -6
- package/dist/shared/icons/FilterIcon.svelte.d.ts +14 -6
- package/dist/shared/icons/Padlock.svelte +6 -2
- package/dist/shared/icons/Padlock.svelte.d.ts +4 -25
- package/dist/shared/icons/SelectionButtons.svelte +23 -8
- package/dist/shared/icons/SelectionButtons.svelte.d.ts +4 -18
- package/dist/shared/icons/SortButtonDown.svelte +15 -4
- package/dist/shared/icons/SortButtonDown.svelte.d.ts +4 -25
- package/dist/shared/icons/SortButtonUp.svelte +15 -5
- package/dist/shared/icons/SortButtonUp.svelte.d.ts +4 -25
- package/dist/shared/icons/SortIcon.svelte +13 -7
- package/dist/shared/icons/SortIcon.svelte.d.ts +7 -21
- package/dist/shared/tanstack/index.d.ts +3 -0
- package/dist/shared/tanstack/index.js +3 -0
- package/dist/shared/tanstack/table.svelte.d.ts +26 -0
- package/dist/shared/tanstack/table.svelte.js +102 -0
- package/dist/shared/tanstack/virtual.svelte.d.ts +14 -0
- package/dist/shared/tanstack/virtual.svelte.js +76 -0
- package/dist/shared/types.d.ts +2 -0
- package/dist/shared/utils/filter.d.ts +5 -0
- package/dist/shared/utils/filter.js +62 -0
- package/dist/shared/utils/selection_utils.js +1 -1
- package/dist/shared/utils/table_utils.d.ts +1 -14
- package/dist/shared/utils/table_utils.js +0 -61
- package/dist/standalone/Index.svelte +71 -46
- package/dist/standalone/Index.svelte.d.ts +4 -23
- package/dist/types.d.ts +32 -0
- package/dist/types.js +1 -0
- package/package.json +10 -9
- package/shared/BooleanCell.svelte +12 -6
- package/shared/CellMenu.svelte +74 -49
- package/shared/CellMenuButton.svelte +3 -3
- package/shared/CellMenuIcons.svelte +1 -1
- package/shared/DataCell.svelte +189 -0
- package/shared/EditableCell.svelte +88 -64
- package/shared/EmptyRowButton.svelte +2 -2
- package/shared/FilterMenu.svelte +26 -18
- package/shared/HeaderCell.svelte +218 -0
- package/shared/RowNumber.svelte +4 -2
- package/shared/Table.svelte +1037 -949
- package/shared/Toolbar.svelte +32 -22
- package/shared/column_measurement.svelte.ts +103 -0
- package/shared/icons/FilterIcon.svelte +14 -6
- package/shared/icons/Padlock.svelte +6 -2
- package/shared/icons/SelectionButtons.svelte +23 -8
- package/shared/icons/SortButtonDown.svelte +15 -4
- package/shared/icons/SortButtonUp.svelte +15 -5
- package/shared/icons/SortIcon.svelte +13 -7
- package/shared/tanstack/index.ts +23 -0
- package/shared/tanstack/table.svelte.ts +117 -0
- package/shared/tanstack/virtual.svelte.ts +105 -0
- package/shared/types.ts +3 -0
- package/shared/utils/filter.ts +66 -0
- package/shared/utils/selection_utils.ts +1 -1
- package/shared/utils/table_utils.ts +1 -100
- package/standalone/Index.svelte +71 -46
- package/test/filter.test.ts +350 -0
- package/test/selection_utils.test.ts +416 -0
- package/test/table_utils.test.ts +45 -112
- package/types.ts +34 -0
- package/dist/shared/TableCell.svelte +0 -330
- package/dist/shared/TableCell.svelte.d.ts +0 -66
- package/dist/shared/TableHeader.svelte +0 -344
- package/dist/shared/TableHeader.svelte.d.ts +0 -61
- package/dist/shared/VirtualTable.svelte +0 -379
- package/dist/shared/VirtualTable.svelte.d.ts +0 -42
- package/dist/shared/context/dataframe_context.d.ts +0 -180
- package/dist/shared/context/dataframe_context.js +0 -412
- package/dist/shared/icons/SortArrowDown.svelte +0 -25
- package/dist/shared/icons/SortArrowDown.svelte.d.ts +0 -20
- package/dist/shared/icons/SortArrowUp.svelte +0 -25
- package/dist/shared/icons/SortArrowUp.svelte.d.ts +0 -20
- package/dist/shared/utils/data_processing.d.ts +0 -14
- package/dist/shared/utils/data_processing.js +0 -47
- package/dist/shared/utils/drag_utils.d.ts +0 -15
- package/dist/shared/utils/drag_utils.js +0 -67
- package/dist/shared/utils/filter_utils.d.ts +0 -29
- package/dist/shared/utils/filter_utils.js +0 -123
- package/dist/shared/utils/keyboard_utils.d.ts +0 -3
- package/dist/shared/utils/keyboard_utils.js +0 -236
- package/dist/shared/utils/menu_utils.d.ts +0 -42
- package/dist/shared/utils/menu_utils.js +0 -58
- package/dist/shared/utils/sort_utils.d.ts +0 -26
- package/dist/shared/utils/sort_utils.js +0 -59
- package/shared/TableCell.svelte +0 -330
- package/shared/TableHeader.svelte +0 -344
- package/shared/VirtualTable.svelte +0 -379
- package/shared/context/dataframe_context.ts +0 -701
- package/shared/icons/SortArrowDown.svelte +0 -25
- package/shared/icons/SortArrowUp.svelte +0 -25
- package/shared/utils/data_processing.ts +0 -77
- package/shared/utils/drag_utils.ts +0 -105
- package/shared/utils/filter_utils.ts +0 -208
- package/shared/utils/keyboard_utils.ts +0 -309
- package/shared/utils/menu_utils.ts +0 -115
- package/shared/utils/sort_utils.ts +0 -91
- package/test/sort_utils.test.ts +0 -323
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom filter function for TanStack Table that handles Gradio's
|
|
3
|
+
* { dtype, filter, value } column filter format.
|
|
4
|
+
*/
|
|
5
|
+
export function gradio_filter_fn(
|
|
6
|
+
row: any,
|
|
7
|
+
columnId: string,
|
|
8
|
+
filterValue: any
|
|
9
|
+
): boolean {
|
|
10
|
+
const { dtype, filter, value: fval } = filterValue;
|
|
11
|
+
const cell_value = String(row.getValue(columnId) ?? "");
|
|
12
|
+
const compare_val = fval ?? "";
|
|
13
|
+
|
|
14
|
+
if (dtype === "number") {
|
|
15
|
+
const num = parseFloat(cell_value);
|
|
16
|
+
const target = parseFloat(compare_val);
|
|
17
|
+
if (isNaN(num) || isNaN(target)) {
|
|
18
|
+
if (filter === "Is empty") return cell_value.trim() === "";
|
|
19
|
+
if (filter === "Is not empty") return cell_value.trim() !== "";
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
switch (filter) {
|
|
23
|
+
case "=":
|
|
24
|
+
return num === target;
|
|
25
|
+
case "≠":
|
|
26
|
+
return num !== target;
|
|
27
|
+
case ">":
|
|
28
|
+
return num > target;
|
|
29
|
+
case "<":
|
|
30
|
+
return num < target;
|
|
31
|
+
case "≥":
|
|
32
|
+
return num >= target;
|
|
33
|
+
case "≤":
|
|
34
|
+
return num <= target;
|
|
35
|
+
case "Is empty":
|
|
36
|
+
return cell_value.trim() === "";
|
|
37
|
+
case "Is not empty":
|
|
38
|
+
return cell_value.trim() !== "";
|
|
39
|
+
default:
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const lower = cell_value.toLowerCase();
|
|
45
|
+
const target_lower = compare_val.toLowerCase();
|
|
46
|
+
switch (filter) {
|
|
47
|
+
case "Contains":
|
|
48
|
+
return lower.includes(target_lower);
|
|
49
|
+
case "Does not contain":
|
|
50
|
+
return !lower.includes(target_lower);
|
|
51
|
+
case "Starts with":
|
|
52
|
+
return lower.startsWith(target_lower);
|
|
53
|
+
case "Ends with":
|
|
54
|
+
return lower.endsWith(target_lower);
|
|
55
|
+
case "Is":
|
|
56
|
+
return lower === target_lower;
|
|
57
|
+
case "Is not":
|
|
58
|
+
return lower !== target_lower;
|
|
59
|
+
case "Is empty":
|
|
60
|
+
return cell_value.trim() === "";
|
|
61
|
+
case "Is not empty":
|
|
62
|
+
return cell_value.trim() !== "";
|
|
63
|
+
default:
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -37,7 +37,7 @@ export function get_range_selection(
|
|
|
37
37
|
const max_col = Math.max(start_col, end_col);
|
|
38
38
|
|
|
39
39
|
const cells: CellCoordinate[] = [];
|
|
40
|
-
//
|
|
40
|
+
// add the start cell as the "anchor" cell so that when
|
|
41
41
|
// we press shift+arrow keys, the selection will always
|
|
42
42
|
// include the anchor cell.
|
|
43
43
|
cells.push(start);
|
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CellValue,
|
|
3
|
-
Headers,
|
|
4
|
-
HeadersWithIDs,
|
|
5
|
-
TableCell,
|
|
6
|
-
TableData
|
|
7
|
-
} from "../types";
|
|
8
|
-
import { sort_data } from "./sort_utils";
|
|
9
|
-
import { filter_data } from "./filter_utils";
|
|
10
|
-
import type { SortDirection } from "./sort_utils";
|
|
11
|
-
import type { FilterDatatype } from "./filter_utils";
|
|
1
|
+
import type { CellValue, Headers, HeadersWithIDs, TableData } from "../types";
|
|
12
2
|
import { dsvFormat } from "d3-dsv";
|
|
13
3
|
|
|
14
4
|
export function make_cell_id(row: number, col: number): string {
|
|
@@ -19,94 +9,6 @@ export function make_header_id(col: number): string {
|
|
|
19
9
|
return `header-${col}`;
|
|
20
10
|
}
|
|
21
11
|
|
|
22
|
-
export function get_max(data: TableData): TableCell[] {
|
|
23
|
-
if (!data || !data.length) return [];
|
|
24
|
-
let max = data[0].slice();
|
|
25
|
-
for (let i = 0; i < data.length; i++) {
|
|
26
|
-
for (let j = 0; j < data[i].length; j++) {
|
|
27
|
-
if (`${max[j].value}`.length < `${data[i][j].value}`.length) {
|
|
28
|
-
max[j] = data[i][j];
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return max;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function sort_table_data(
|
|
36
|
-
data: TableData,
|
|
37
|
-
display_value: string[][] | null,
|
|
38
|
-
styling: string[][] | null,
|
|
39
|
-
sort_columns: { col: number; direction: SortDirection }[]
|
|
40
|
-
): void {
|
|
41
|
-
if (!sort_columns.length) return;
|
|
42
|
-
if (!data || !data.length) return;
|
|
43
|
-
|
|
44
|
-
const indices = sort_data(data, sort_columns);
|
|
45
|
-
|
|
46
|
-
const new_data = indices.map((i: number) => data[i]);
|
|
47
|
-
data.splice(0, data.length, ...new_data);
|
|
48
|
-
|
|
49
|
-
if (display_value) {
|
|
50
|
-
const new_display = indices.map((i: number) => display_value[i]);
|
|
51
|
-
display_value.splice(0, display_value.length, ...new_display);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (styling) {
|
|
55
|
-
const new_styling = indices.map((i: number) => styling[i]);
|
|
56
|
-
styling.splice(0, styling.length, ...new_styling);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function filter_table_data(
|
|
61
|
-
data: TableData,
|
|
62
|
-
display_value: string[][] | null,
|
|
63
|
-
styling: string[][] | null,
|
|
64
|
-
filter_columns: {
|
|
65
|
-
col: number;
|
|
66
|
-
datatype: FilterDatatype;
|
|
67
|
-
filter: string;
|
|
68
|
-
value: string;
|
|
69
|
-
}[],
|
|
70
|
-
original_data?: TableData,
|
|
71
|
-
original_display_value?: string[][] | null,
|
|
72
|
-
original_styling?: string[][] | null
|
|
73
|
-
): void {
|
|
74
|
-
const base_data = original_data ?? data;
|
|
75
|
-
const base_display_value = original_display_value ?? display_value;
|
|
76
|
-
const base_styling = original_styling ?? styling;
|
|
77
|
-
|
|
78
|
-
if (!filter_columns.length) {
|
|
79
|
-
data.splice(0, data.length, ...base_data.map((row) => [...row]));
|
|
80
|
-
if (display_value && base_display_value) {
|
|
81
|
-
display_value.splice(
|
|
82
|
-
0,
|
|
83
|
-
display_value.length,
|
|
84
|
-
...base_display_value.map((row) => [...row])
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
if (styling && base_styling) {
|
|
88
|
-
styling.splice(0, styling.length, ...base_styling.map((row) => [...row]));
|
|
89
|
-
}
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
if (!data || !data.length) return;
|
|
93
|
-
|
|
94
|
-
const indices = filter_data(base_data, filter_columns);
|
|
95
|
-
|
|
96
|
-
const new_data = indices.map((i: number) => base_data[i]);
|
|
97
|
-
data.splice(0, data.length, ...new_data);
|
|
98
|
-
|
|
99
|
-
if (display_value && base_display_value) {
|
|
100
|
-
const new_display = indices.map((i: number) => base_display_value[i]);
|
|
101
|
-
display_value.splice(0, display_value.length, ...new_display);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (styling && base_styling) {
|
|
105
|
-
const new_styling = indices.map((i: number) => base_styling[i]);
|
|
106
|
-
styling.splice(0, styling.length, ...new_styling);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
12
|
export async function copy_table_data(
|
|
111
13
|
data: TableData,
|
|
112
14
|
selected_cells: [number, number][] | null
|
|
@@ -145,7 +47,6 @@ export async function copy_table_data(
|
|
|
145
47
|
}
|
|
146
48
|
}
|
|
147
49
|
|
|
148
|
-
// File Import/Export
|
|
149
50
|
export function guess_delimiter(
|
|
150
51
|
text: string,
|
|
151
52
|
possibleDelimiters: string[]
|
package/standalone/Index.svelte
CHANGED
|
@@ -5,7 +5,52 @@
|
|
|
5
5
|
import type { I18nFormatter } from "@gradio/utils";
|
|
6
6
|
import { default_i18n } from "./default_i18n";
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
let {
|
|
9
|
+
i18n = undefined,
|
|
10
|
+
value = $bindable({
|
|
11
|
+
data: [["", "", ""]],
|
|
12
|
+
headers: ["1", "2", "3"],
|
|
13
|
+
metadata: null
|
|
14
|
+
}),
|
|
15
|
+
datatype = "str",
|
|
16
|
+
interactive = true,
|
|
17
|
+
show_row_numbers = false,
|
|
18
|
+
max_height = 500,
|
|
19
|
+
show_search = "none",
|
|
20
|
+
wrap = false,
|
|
21
|
+
line_breaks = true,
|
|
22
|
+
column_widths = [],
|
|
23
|
+
max_chars = undefined,
|
|
24
|
+
pinned_columns = 0,
|
|
25
|
+
static_columns = [],
|
|
26
|
+
fullscreen = $bindable(false),
|
|
27
|
+
label = null,
|
|
28
|
+
show_label = true,
|
|
29
|
+
latex_delimiters = [],
|
|
30
|
+
col_count = undefined,
|
|
31
|
+
row_count = undefined
|
|
32
|
+
}: {
|
|
33
|
+
i18n?: I18nFormatter | undefined;
|
|
34
|
+
value?: DataframeValue;
|
|
35
|
+
datatype?: Datatype | Datatype[];
|
|
36
|
+
interactive?: boolean;
|
|
37
|
+
show_row_numbers?: boolean;
|
|
38
|
+
max_height?: number;
|
|
39
|
+
show_search?: "none" | "search" | "filter";
|
|
40
|
+
wrap?: boolean;
|
|
41
|
+
line_breaks?: boolean;
|
|
42
|
+
column_widths?: string[];
|
|
43
|
+
max_chars?: number | undefined;
|
|
44
|
+
pinned_columns?: number;
|
|
45
|
+
static_columns?: (string | number)[];
|
|
46
|
+
fullscreen?: boolean;
|
|
47
|
+
label?: string | null;
|
|
48
|
+
show_label?: boolean;
|
|
49
|
+
latex_delimiters?: any[];
|
|
50
|
+
col_count?: [number, "fixed" | "dynamic"] | undefined;
|
|
51
|
+
row_count?: [number, "fixed" | "dynamic"] | undefined;
|
|
52
|
+
} = $props();
|
|
53
|
+
|
|
9
54
|
const i18n_fn = (key: string | null | undefined): string => {
|
|
10
55
|
if (!key) return "";
|
|
11
56
|
if (typeof i18n === "function") return (i18n as any)(key);
|
|
@@ -14,31 +59,7 @@
|
|
|
14
59
|
return default_i18n[key] ?? key;
|
|
15
60
|
};
|
|
16
61
|
|
|
17
|
-
|
|
18
|
-
data: [["", "", ""]],
|
|
19
|
-
headers: ["1", "2", "3"],
|
|
20
|
-
metadata: null
|
|
21
|
-
};
|
|
22
|
-
export let datatype: Datatype | Datatype[] = "str";
|
|
23
|
-
export let interactive = true;
|
|
24
|
-
export let show_row_numbers = false;
|
|
25
|
-
export let max_height = 500;
|
|
26
|
-
export let show_search: "none" | "search" | "filter" = "none";
|
|
27
|
-
export let wrap = false;
|
|
28
|
-
export let line_breaks = true;
|
|
29
|
-
export let column_widths: string[] = [];
|
|
30
|
-
export let max_chars: number | undefined = undefined;
|
|
31
|
-
export let pinned_columns = 0;
|
|
32
|
-
export let static_columns: (string | number)[] = [];
|
|
33
|
-
export let fullscreen = false;
|
|
34
|
-
export let label: string | null = null;
|
|
35
|
-
export let show_label = true;
|
|
36
|
-
export let latex_delimiters: any[] = [];
|
|
37
|
-
export let col_count: [number, "fixed" | "dynamic"] | undefined = undefined;
|
|
38
|
-
export let row_count: [number, "fixed" | "dynamic"] | undefined = undefined;
|
|
39
|
-
|
|
40
|
-
// mirrors default row count and column count logic in dataframe.py
|
|
41
|
-
$: resolved_row_count = (() => {
|
|
62
|
+
let resolved_row_count = $derived.by(() => {
|
|
42
63
|
if (
|
|
43
64
|
row_count &&
|
|
44
65
|
Array.isArray(row_count) &&
|
|
@@ -49,8 +70,9 @@
|
|
|
49
70
|
return row_count as [number, "fixed" | "dynamic"];
|
|
50
71
|
}
|
|
51
72
|
return [1, "dynamic"] as [number, "fixed" | "dynamic"];
|
|
52
|
-
})
|
|
53
|
-
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
let resolved_col_count_base = $derived.by(() => {
|
|
54
76
|
if (
|
|
55
77
|
col_count &&
|
|
56
78
|
Array.isArray(col_count) &&
|
|
@@ -65,14 +87,21 @@
|
|
|
65
87
|
? value.headers.length
|
|
66
88
|
: 3;
|
|
67
89
|
return [headerLength, "dynamic"] as [number, "fixed" | "dynamic"];
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
let resolved_col_count = $derived.by(() => {
|
|
93
|
+
if (
|
|
94
|
+
static_columns &&
|
|
95
|
+
static_columns.length > 0 &&
|
|
96
|
+
resolved_col_count_base[1] !== "fixed"
|
|
97
|
+
) {
|
|
98
|
+
return [resolved_col_count_base[0], "fixed"] as [
|
|
99
|
+
number,
|
|
100
|
+
"fixed" | "dynamic"
|
|
101
|
+
];
|
|
102
|
+
}
|
|
103
|
+
return resolved_col_count_base;
|
|
104
|
+
});
|
|
76
105
|
|
|
77
106
|
let root = "";
|
|
78
107
|
|
|
@@ -91,8 +120,8 @@
|
|
|
91
120
|
<Table
|
|
92
121
|
values={value.data}
|
|
93
122
|
headers={value.headers}
|
|
94
|
-
display_value={value?.metadata?.display_value}
|
|
95
|
-
styling={value?.metadata?.styling}
|
|
123
|
+
display_value={value?.metadata?.display_value ?? null}
|
|
124
|
+
styling={value?.metadata?.styling ?? null}
|
|
96
125
|
{datatype}
|
|
97
126
|
editable={interactive}
|
|
98
127
|
{show_row_numbers}
|
|
@@ -113,15 +142,11 @@
|
|
|
113
142
|
row_count={resolved_row_count}
|
|
114
143
|
{root}
|
|
115
144
|
i18n={i18n_fn}
|
|
116
|
-
|
|
117
|
-
value.data =
|
|
118
|
-
value.headers =
|
|
145
|
+
onchange={(detail) => {
|
|
146
|
+
value.data = detail.data;
|
|
147
|
+
value.headers = detail.headers;
|
|
119
148
|
}}
|
|
120
|
-
|
|
121
|
-
on:keydown
|
|
122
|
-
on:input
|
|
123
|
-
on:select
|
|
124
|
-
on:fullscreen={(e) => (fullscreen = e.detail)}
|
|
149
|
+
onfullscreen={() => (fullscreen = !fullscreen)}
|
|
125
150
|
upload={async () => null}
|
|
126
151
|
stream_handler={() => new EventSource("about:blank")}
|
|
127
152
|
/>
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { gradio_filter_fn } from "../shared/utils/filter";
|
|
3
|
+
|
|
4
|
+
const make_row = (value: any) => ({
|
|
5
|
+
getValue: (_col: string) => value
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
describe("gradio_filter_fn", () => {
|
|
9
|
+
describe("number filters", () => {
|
|
10
|
+
test("= matches exact number", () => {
|
|
11
|
+
expect(
|
|
12
|
+
gradio_filter_fn(make_row(42), "col_0", {
|
|
13
|
+
dtype: "number",
|
|
14
|
+
filter: "=",
|
|
15
|
+
value: "42"
|
|
16
|
+
})
|
|
17
|
+
).toBe(true);
|
|
18
|
+
expect(
|
|
19
|
+
gradio_filter_fn(make_row(42), "col_0", {
|
|
20
|
+
dtype: "number",
|
|
21
|
+
filter: "=",
|
|
22
|
+
value: "43"
|
|
23
|
+
})
|
|
24
|
+
).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("≠ excludes exact number", () => {
|
|
28
|
+
expect(
|
|
29
|
+
gradio_filter_fn(make_row(42), "col_0", {
|
|
30
|
+
dtype: "number",
|
|
31
|
+
filter: "≠",
|
|
32
|
+
value: "42"
|
|
33
|
+
})
|
|
34
|
+
).toBe(false);
|
|
35
|
+
expect(
|
|
36
|
+
gradio_filter_fn(make_row(42), "col_0", {
|
|
37
|
+
dtype: "number",
|
|
38
|
+
filter: "≠",
|
|
39
|
+
value: "43"
|
|
40
|
+
})
|
|
41
|
+
).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("> greater than", () => {
|
|
45
|
+
expect(
|
|
46
|
+
gradio_filter_fn(make_row(10), "col_0", {
|
|
47
|
+
dtype: "number",
|
|
48
|
+
filter: ">",
|
|
49
|
+
value: "5"
|
|
50
|
+
})
|
|
51
|
+
).toBe(true);
|
|
52
|
+
expect(
|
|
53
|
+
gradio_filter_fn(make_row(5), "col_0", {
|
|
54
|
+
dtype: "number",
|
|
55
|
+
filter: ">",
|
|
56
|
+
value: "5"
|
|
57
|
+
})
|
|
58
|
+
).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("< less than", () => {
|
|
62
|
+
expect(
|
|
63
|
+
gradio_filter_fn(make_row(3), "col_0", {
|
|
64
|
+
dtype: "number",
|
|
65
|
+
filter: "<",
|
|
66
|
+
value: "5"
|
|
67
|
+
})
|
|
68
|
+
).toBe(true);
|
|
69
|
+
expect(
|
|
70
|
+
gradio_filter_fn(make_row(5), "col_0", {
|
|
71
|
+
dtype: "number",
|
|
72
|
+
filter: "<",
|
|
73
|
+
value: "5"
|
|
74
|
+
})
|
|
75
|
+
).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("≥ greater than or equal", () => {
|
|
79
|
+
expect(
|
|
80
|
+
gradio_filter_fn(make_row(5), "col_0", {
|
|
81
|
+
dtype: "number",
|
|
82
|
+
filter: "≥",
|
|
83
|
+
value: "5"
|
|
84
|
+
})
|
|
85
|
+
).toBe(true);
|
|
86
|
+
expect(
|
|
87
|
+
gradio_filter_fn(make_row(4), "col_0", {
|
|
88
|
+
dtype: "number",
|
|
89
|
+
filter: "≥",
|
|
90
|
+
value: "5"
|
|
91
|
+
})
|
|
92
|
+
).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("≤ less than or equal", () => {
|
|
96
|
+
expect(
|
|
97
|
+
gradio_filter_fn(make_row(5), "col_0", {
|
|
98
|
+
dtype: "number",
|
|
99
|
+
filter: "≤",
|
|
100
|
+
value: "5"
|
|
101
|
+
})
|
|
102
|
+
).toBe(true);
|
|
103
|
+
expect(
|
|
104
|
+
gradio_filter_fn(make_row(6), "col_0", {
|
|
105
|
+
dtype: "number",
|
|
106
|
+
filter: "≤",
|
|
107
|
+
value: "5"
|
|
108
|
+
})
|
|
109
|
+
).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("Is empty on empty string", () => {
|
|
113
|
+
expect(
|
|
114
|
+
gradio_filter_fn(make_row(""), "col_0", {
|
|
115
|
+
dtype: "number",
|
|
116
|
+
filter: "Is empty",
|
|
117
|
+
value: ""
|
|
118
|
+
})
|
|
119
|
+
).toBe(true);
|
|
120
|
+
expect(
|
|
121
|
+
gradio_filter_fn(make_row("42"), "col_0", {
|
|
122
|
+
dtype: "number",
|
|
123
|
+
filter: "Is empty",
|
|
124
|
+
value: ""
|
|
125
|
+
})
|
|
126
|
+
).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("Is not empty on non-empty string", () => {
|
|
130
|
+
expect(
|
|
131
|
+
gradio_filter_fn(make_row("42"), "col_0", {
|
|
132
|
+
dtype: "number",
|
|
133
|
+
filter: "Is not empty",
|
|
134
|
+
value: ""
|
|
135
|
+
})
|
|
136
|
+
).toBe(true);
|
|
137
|
+
expect(
|
|
138
|
+
gradio_filter_fn(make_row(""), "col_0", {
|
|
139
|
+
dtype: "number",
|
|
140
|
+
filter: "Is not empty",
|
|
141
|
+
value: ""
|
|
142
|
+
})
|
|
143
|
+
).toBe(false);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("NaN target falls through to true", () => {
|
|
147
|
+
expect(
|
|
148
|
+
gradio_filter_fn(make_row(42), "col_0", {
|
|
149
|
+
dtype: "number",
|
|
150
|
+
filter: "=",
|
|
151
|
+
value: "abc"
|
|
152
|
+
})
|
|
153
|
+
).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("NaN cell value falls through to true", () => {
|
|
157
|
+
expect(
|
|
158
|
+
gradio_filter_fn(make_row("abc"), "col_0", {
|
|
159
|
+
dtype: "number",
|
|
160
|
+
filter: "=",
|
|
161
|
+
value: "42"
|
|
162
|
+
})
|
|
163
|
+
).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe("string filters", () => {
|
|
168
|
+
test("Contains (case-insensitive)", () => {
|
|
169
|
+
expect(
|
|
170
|
+
gradio_filter_fn(make_row("Hello World"), "col_0", {
|
|
171
|
+
dtype: "string",
|
|
172
|
+
filter: "Contains",
|
|
173
|
+
value: "hello"
|
|
174
|
+
})
|
|
175
|
+
).toBe(true);
|
|
176
|
+
expect(
|
|
177
|
+
gradio_filter_fn(make_row("Hello World"), "col_0", {
|
|
178
|
+
dtype: "string",
|
|
179
|
+
filter: "Contains",
|
|
180
|
+
value: "xyz"
|
|
181
|
+
})
|
|
182
|
+
).toBe(false);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("Does not contain", () => {
|
|
186
|
+
expect(
|
|
187
|
+
gradio_filter_fn(make_row("Hello World"), "col_0", {
|
|
188
|
+
dtype: "string",
|
|
189
|
+
filter: "Does not contain",
|
|
190
|
+
value: "xyz"
|
|
191
|
+
})
|
|
192
|
+
).toBe(true);
|
|
193
|
+
expect(
|
|
194
|
+
gradio_filter_fn(make_row("Hello World"), "col_0", {
|
|
195
|
+
dtype: "string",
|
|
196
|
+
filter: "Does not contain",
|
|
197
|
+
value: "hello"
|
|
198
|
+
})
|
|
199
|
+
).toBe(false);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test("Starts with", () => {
|
|
203
|
+
expect(
|
|
204
|
+
gradio_filter_fn(make_row("Hello World"), "col_0", {
|
|
205
|
+
dtype: "string",
|
|
206
|
+
filter: "Starts with",
|
|
207
|
+
value: "hello"
|
|
208
|
+
})
|
|
209
|
+
).toBe(true);
|
|
210
|
+
expect(
|
|
211
|
+
gradio_filter_fn(make_row("Hello World"), "col_0", {
|
|
212
|
+
dtype: "string",
|
|
213
|
+
filter: "Starts with",
|
|
214
|
+
value: "world"
|
|
215
|
+
})
|
|
216
|
+
).toBe(false);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test("Ends with", () => {
|
|
220
|
+
expect(
|
|
221
|
+
gradio_filter_fn(make_row("Hello World"), "col_0", {
|
|
222
|
+
dtype: "string",
|
|
223
|
+
filter: "Ends with",
|
|
224
|
+
value: "world"
|
|
225
|
+
})
|
|
226
|
+
).toBe(true);
|
|
227
|
+
expect(
|
|
228
|
+
gradio_filter_fn(make_row("Hello World"), "col_0", {
|
|
229
|
+
dtype: "string",
|
|
230
|
+
filter: "Ends with",
|
|
231
|
+
value: "hello"
|
|
232
|
+
})
|
|
233
|
+
).toBe(false);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test("Is (exact match, case-insensitive)", () => {
|
|
237
|
+
expect(
|
|
238
|
+
gradio_filter_fn(make_row("Hello"), "col_0", {
|
|
239
|
+
dtype: "string",
|
|
240
|
+
filter: "Is",
|
|
241
|
+
value: "hello"
|
|
242
|
+
})
|
|
243
|
+
).toBe(true);
|
|
244
|
+
expect(
|
|
245
|
+
gradio_filter_fn(make_row("Hello World"), "col_0", {
|
|
246
|
+
dtype: "string",
|
|
247
|
+
filter: "Is",
|
|
248
|
+
value: "hello"
|
|
249
|
+
})
|
|
250
|
+
).toBe(false);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
test("Is not", () => {
|
|
254
|
+
expect(
|
|
255
|
+
gradio_filter_fn(make_row("Hello World"), "col_0", {
|
|
256
|
+
dtype: "string",
|
|
257
|
+
filter: "Is not",
|
|
258
|
+
value: "hello"
|
|
259
|
+
})
|
|
260
|
+
).toBe(true);
|
|
261
|
+
expect(
|
|
262
|
+
gradio_filter_fn(make_row("Hello"), "col_0", {
|
|
263
|
+
dtype: "string",
|
|
264
|
+
filter: "Is not",
|
|
265
|
+
value: "hello"
|
|
266
|
+
})
|
|
267
|
+
).toBe(false);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test("Is empty", () => {
|
|
271
|
+
expect(
|
|
272
|
+
gradio_filter_fn(make_row(""), "col_0", {
|
|
273
|
+
dtype: "string",
|
|
274
|
+
filter: "Is empty",
|
|
275
|
+
value: ""
|
|
276
|
+
})
|
|
277
|
+
).toBe(true);
|
|
278
|
+
expect(
|
|
279
|
+
gradio_filter_fn(make_row(" "), "col_0", {
|
|
280
|
+
dtype: "string",
|
|
281
|
+
filter: "Is empty",
|
|
282
|
+
value: ""
|
|
283
|
+
})
|
|
284
|
+
).toBe(true);
|
|
285
|
+
expect(
|
|
286
|
+
gradio_filter_fn(make_row("hello"), "col_0", {
|
|
287
|
+
dtype: "string",
|
|
288
|
+
filter: "Is empty",
|
|
289
|
+
value: ""
|
|
290
|
+
})
|
|
291
|
+
).toBe(false);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test("Is not empty", () => {
|
|
295
|
+
expect(
|
|
296
|
+
gradio_filter_fn(make_row("hello"), "col_0", {
|
|
297
|
+
dtype: "string",
|
|
298
|
+
filter: "Is not empty",
|
|
299
|
+
value: ""
|
|
300
|
+
})
|
|
301
|
+
).toBe(true);
|
|
302
|
+
expect(
|
|
303
|
+
gradio_filter_fn(make_row(""), "col_0", {
|
|
304
|
+
dtype: "string",
|
|
305
|
+
filter: "Is not empty",
|
|
306
|
+
value: ""
|
|
307
|
+
})
|
|
308
|
+
).toBe(false);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
describe("edge cases", () => {
|
|
313
|
+
test("null cell value coerced to empty string", () => {
|
|
314
|
+
expect(
|
|
315
|
+
gradio_filter_fn(make_row(null), "col_0", {
|
|
316
|
+
dtype: "string",
|
|
317
|
+
filter: "Is empty",
|
|
318
|
+
value: ""
|
|
319
|
+
})
|
|
320
|
+
).toBe(true);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
test("undefined filter value coerced to empty string", () => {
|
|
324
|
+
expect(
|
|
325
|
+
gradio_filter_fn(make_row("hello"), "col_0", {
|
|
326
|
+
dtype: "string",
|
|
327
|
+
filter: "Contains",
|
|
328
|
+
value: undefined
|
|
329
|
+
})
|
|
330
|
+
).toBe(true);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test("unknown filter returns true (passthrough)", () => {
|
|
334
|
+
expect(
|
|
335
|
+
gradio_filter_fn(make_row("hello"), "col_0", {
|
|
336
|
+
dtype: "string",
|
|
337
|
+
filter: "UnknownFilter",
|
|
338
|
+
value: "x"
|
|
339
|
+
})
|
|
340
|
+
).toBe(true);
|
|
341
|
+
expect(
|
|
342
|
+
gradio_filter_fn(make_row(42), "col_0", {
|
|
343
|
+
dtype: "number",
|
|
344
|
+
filter: "UnknownFilter",
|
|
345
|
+
value: "5"
|
|
346
|
+
})
|
|
347
|
+
).toBe(true);
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
});
|