@gradio/dataframe 0.17.17 → 0.18.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.
@@ -0,0 +1,207 @@
1
+ import { filter_table_data } from "./table_utils";
2
+
3
+ export type FilterDatatype = "string" | "number";
4
+
5
+ export function filter_data(
6
+ data: { id: string; value: string | number }[][],
7
+ filter_columns: {
8
+ col: number;
9
+ datatype: FilterDatatype;
10
+ filter: string;
11
+ value: string;
12
+ }[]
13
+ ): number[] {
14
+ if (!data || !data.length || !data[0]) {
15
+ return [];
16
+ }
17
+ let row_indices = [...Array(data.length)].map((_, i) => i);
18
+
19
+ if (filter_columns.length > 0) {
20
+ filter_columns.forEach((column) => {
21
+ if (column.datatype === "string") {
22
+ switch (column.filter) {
23
+ case "Contains":
24
+ row_indices = row_indices.filter((i) =>
25
+ data[i][column.col]?.value.toString().includes(column.value)
26
+ );
27
+ break;
28
+ case "Does not contain":
29
+ row_indices = row_indices.filter(
30
+ (i) =>
31
+ !data[i][column.col]?.value.toString().includes(column.value)
32
+ );
33
+ break;
34
+ case "Starts with":
35
+ row_indices = row_indices.filter((i) =>
36
+ data[i][column.col]?.value.toString().startsWith(column.value)
37
+ );
38
+ break;
39
+ case "Ends with":
40
+ row_indices = row_indices.filter((i) =>
41
+ data[i][column.col]?.value.toString().endsWith(column.value)
42
+ );
43
+ break;
44
+ case "Is":
45
+ row_indices = row_indices.filter(
46
+ (i) => data[i][column.col]?.value.toString() === column.value
47
+ );
48
+ break;
49
+ case "Is not":
50
+ row_indices = row_indices.filter(
51
+ (i) => !(data[i][column.col]?.value.toString() === column.value)
52
+ );
53
+ break;
54
+ case "Is empty":
55
+ row_indices = row_indices.filter(
56
+ (i) => data[i][column.col]?.value.toString() === ""
57
+ );
58
+ break;
59
+ case "Is not empty":
60
+ row_indices = row_indices.filter(
61
+ (i) => !(data[i][column.col]?.value.toString() === "")
62
+ );
63
+ break;
64
+ }
65
+ } else if (column.datatype === "number") {
66
+ switch (column.filter) {
67
+ case "=":
68
+ row_indices = row_indices.filter((i) => {
69
+ if (
70
+ !isNaN(Number(data[i][column.col]?.value)) &&
71
+ !isNaN(Number(column.value))
72
+ ) {
73
+ return (
74
+ Number(data[i][column.col]?.value) === Number(column.value)
75
+ );
76
+ }
77
+ return false;
78
+ });
79
+ break;
80
+ case "≠":
81
+ row_indices = row_indices.filter((i) => {
82
+ if (
83
+ !isNaN(Number(data[i][column.col]?.value)) &&
84
+ !isNaN(Number(column.value))
85
+ ) {
86
+ return !(
87
+ Number(data[i][column.col]?.value) === Number(column.value)
88
+ );
89
+ }
90
+ return false;
91
+ });
92
+ break;
93
+ case ">":
94
+ row_indices = row_indices.filter((i) => {
95
+ if (
96
+ !isNaN(Number(data[i][column.col]?.value)) &&
97
+ !isNaN(Number(column.value))
98
+ ) {
99
+ return (
100
+ Number(data[i][column.col]?.value) > Number(column.value)
101
+ );
102
+ }
103
+ return false;
104
+ });
105
+ break;
106
+ case "<":
107
+ row_indices = row_indices.filter((i) => {
108
+ if (
109
+ !isNaN(Number(data[i][column.col]?.value)) &&
110
+ !isNaN(Number(column.value))
111
+ ) {
112
+ return (
113
+ Number(data[i][column.col]?.value) < Number(column.value)
114
+ );
115
+ }
116
+ return false;
117
+ });
118
+ break;
119
+ case "≥":
120
+ row_indices = row_indices.filter((i) => {
121
+ if (
122
+ !isNaN(Number(data[i][column.col]?.value)) &&
123
+ !isNaN(Number(column.value))
124
+ ) {
125
+ return (
126
+ Number(data[i][column.col]?.value) >= Number(column.value)
127
+ );
128
+ }
129
+ return false;
130
+ });
131
+ break;
132
+ case "≤":
133
+ row_indices = row_indices.filter((i) => {
134
+ if (
135
+ !isNaN(Number(data[i][column.col]?.value)) &&
136
+ !isNaN(Number(column.value))
137
+ ) {
138
+ return (
139
+ Number(data[i][column.col]?.value) <= Number(column.value)
140
+ );
141
+ }
142
+ return false;
143
+ });
144
+ break;
145
+ case "Is empty":
146
+ row_indices = row_indices.filter(
147
+ (i) => data[i][column.col]?.value.toString() === ""
148
+ );
149
+ break;
150
+ case "Is not empty":
151
+ row_indices = row_indices.filter((i) => {
152
+ if (!isNaN(Number(data[i][column.col]?.value))) {
153
+ return !(data[i][column.col]?.value.toString() === "");
154
+ }
155
+ return false;
156
+ });
157
+ break;
158
+ }
159
+ }
160
+ });
161
+ return row_indices;
162
+ }
163
+ return [...Array(data.length)].map((_, i) => i);
164
+ }
165
+
166
+ export function filter_data_and_preserve_selection(
167
+ data: { id: string; value: string | number }[][],
168
+ display_value: string[][] | null,
169
+ styling: string[][] | null,
170
+ filter_columns: {
171
+ col: number;
172
+ datatype: FilterDatatype;
173
+ filter: string;
174
+ value: string;
175
+ }[],
176
+ selected: [number, number] | false,
177
+ get_current_indices: (
178
+ id: string,
179
+ data: { id: string; value: string | number }[][]
180
+ ) => [number, number],
181
+ original_data?: { id: string; value: string | number }[][],
182
+ original_display_value?: string[][] | null,
183
+ original_styling?: string[][] | null
184
+ ): { data: typeof data; selected: [number, number] | false } {
185
+ let id = null;
186
+ if (selected && selected[0] in data && selected[1] in data[selected[0]]) {
187
+ id = data[selected[0]][selected[1]].id;
188
+ }
189
+
190
+ filter_table_data(
191
+ data,
192
+ display_value,
193
+ styling,
194
+ filter_columns,
195
+ original_data,
196
+ original_display_value,
197
+ original_styling
198
+ );
199
+
200
+ let new_selected = selected;
201
+ if (id) {
202
+ const [i, j] = get_current_indices(id, data);
203
+ new_selected = [i, j];
204
+ }
205
+
206
+ return { data, selected: new_selected };
207
+ }
@@ -1,6 +1,8 @@
1
1
  import type { Headers, HeadersWithIDs, TableCell, TableData } from "../types";
2
2
  import { sort_data } from "./sort_utils";
3
+ import { filter_data } from "./filter_utils";
3
4
  import type { SortDirection } from "./sort_utils";
5
+ import type { FilterDatatype } from "./filter_utils";
4
6
  import { dsvFormat } from "d3-dsv";
5
7
 
6
8
  export function make_cell_id(row: number, col: number): string {
@@ -49,6 +51,56 @@ export function sort_table_data(
49
51
  }
50
52
  }
51
53
 
54
+ export function filter_table_data(
55
+ data: TableData,
56
+ display_value: string[][] | null,
57
+ styling: string[][] | null,
58
+ filter_columns: {
59
+ col: number;
60
+ datatype: FilterDatatype;
61
+ filter: string;
62
+ value: string;
63
+ }[],
64
+ original_data?: TableData,
65
+ original_display_value?: string[][] | null,
66
+ original_styling?: string[][] | null
67
+ ): void {
68
+ const base_data = original_data ?? data;
69
+ const base_display_value = original_display_value ?? display_value;
70
+ const base_styling = original_styling ?? styling;
71
+
72
+ if (!filter_columns.length) {
73
+ data.splice(0, data.length, ...base_data.map((row) => [...row]));
74
+ if (display_value && base_display_value) {
75
+ display_value.splice(
76
+ 0,
77
+ display_value.length,
78
+ ...base_display_value.map((row) => [...row])
79
+ );
80
+ }
81
+ if (styling && base_styling) {
82
+ styling.splice(0, styling.length, ...base_styling.map((row) => [...row]));
83
+ }
84
+ return;
85
+ }
86
+ if (!data || !data.length) return;
87
+
88
+ const indices = filter_data(base_data, filter_columns);
89
+
90
+ const new_data = indices.map((i: number) => base_data[i]);
91
+ data.splice(0, data.length, ...new_data);
92
+
93
+ if (display_value && base_display_value) {
94
+ const new_display = indices.map((i: number) => base_display_value[i]);
95
+ display_value.splice(0, display_value.length, ...new_display);
96
+ }
97
+
98
+ if (styling && base_styling) {
99
+ const new_styling = indices.map((i: number) => base_styling[i]);
100
+ styling.splice(0, styling.length, ...new_styling);
101
+ }
102
+ }
103
+
52
104
  export async function copy_table_data(
53
105
  data: TableData,
54
106
  selected_cells: [number, number][] | null