@@ -20,17 +20,14 @@ import type {
20
20
SetFilterValuesFuncParams ,
21
21
SortChangedEvent ,
22
22
} from ' ag-grid-enterprise'
23
- import { computed , ref , shallowRef , watchEffect , type Ref } from ' vue'
23
+ import { computed , onMounted , ref , shallowRef , watchEffect , type Ref } from ' vue'
24
24
import { TableVisualisationTooltip } from ' ./TableVisualization/TableVisualisationTooltip'
25
25
import {
26
26
convertFilterModel ,
27
27
convertSortModel ,
28
28
parseArgument ,
29
29
} from ' ./TableVisualization/TableVizDataSource'
30
- import {
31
- GridFilterModel ,
32
- makeFilterModelList ,
33
- } from ' ./TableVisualization/tableVizFilterUtils'
30
+ import { GridFilterModel , makeFilterModelList } from ' ./TableVisualization/tableVizFilterUtils'
34
31
import { TableVizStatusBar } from ' ./TableVisualization/TableVizStatusBar'
35
32
import { getCellValueType , isNumericType } from ' ./TableVisualization/tableVizUtils'
36
33
@@ -130,6 +127,12 @@ const VECTOR_NODE_TYPE = 'Standard.Base.Data.Vector.Vector'
130
127
const COLUMN_NODE_TYPE = ' Standard.Table.Column.Column'
131
128
const ROW_NODE_TYPE = ' Standard.Table.Row.Row'
132
129
130
+ const rowLimit = ref (0 )
131
+ const page = ref (0 )
132
+ const pageLimit = ref (0 )
133
+ const rowCount = ref (0 )
134
+ const showRowCount = ref (true )
135
+ const isTruncated = ref (false )
133
136
const isCreateNodeEnabled = ref (false )
134
137
const filterModel = ref <GridFilterModel []>([])
135
138
const sortModel = ref <SortModel []>([])
@@ -155,26 +158,55 @@ const columnDefs: Ref<ColDef[]> = ref([])
155
158
const allRowCount = computed (() =>
156
159
typeof props .data === ' object' && ' all_rows_count' in props .data ? props .data .all_rows_count : 0 ,
157
160
)
158
- const isSSRM = computed (() =>
159
- typeof props .data === ' object' && ' is_ssrm' in props .data && props .data .is_ssrm
161
+ const isSSRM = computed (
162
+ () => typeof props .data === ' object' && ' is_ssrm' in props .data && props .data .is_ssrm ,
160
163
)
161
164
const statusBar = computed (() =>
162
165
allRowCount .value ?
163
166
{
164
- statusPanels: [
165
- {
166
- statusPanel: TableVizStatusBar ,
167
- statusPanelParams: {
168
- total: allRowCount .value
169
- },
170
- },
171
- ],
167
+ statusPanels:
168
+ isSSRM .value ?
169
+ [
170
+ {
171
+ statusPanel: TableVizStatusBar ,
172
+ statusPanelParams: {
173
+ total: allRowCount .value ,
174
+ },
175
+ },
176
+ ]
177
+ : [],
172
178
}
173
179
: null ,
174
180
)
175
181
176
182
const textFormatterSelected = ref <TextFormatOptions >(' partial' )
177
183
184
+ const isRowCountSelectorVisible = computed (() => rowCount .value >= 1000 )
185
+
186
+ const selectableRowLimits = computed (() => {
187
+ const defaults = [1000 , 2500 , 5000 , 10000 , 25000 , 50000 , 100000 ].filter (
188
+ (r ) => r <= rowCount .value ,
189
+ )
190
+ if (rowCount .value < 100000 && ! defaults .includes (rowCount .value )) {
191
+ defaults .push (rowCount .value )
192
+ }
193
+ if (! defaults .includes (rowLimit .value )) {
194
+ defaults .push (rowLimit .value )
195
+ }
196
+ return defaults
197
+ })
198
+
199
+ function setRowLimit(newRowLimit : number ) {
200
+ if (newRowLimit !== rowLimit .value ) {
201
+ rowLimit .value = newRowLimit
202
+ config .setPreprocessor (
203
+ ' Standard.Visualization.Table.Visualization' ,
204
+ ' prepare_visualization' ,
205
+ newRowLimit .toString (),
206
+ )
207
+ }
208
+ }
209
+
178
210
const isFilterSortNodeEnabled = computed (
179
211
() => config .nodeType === TABLE_NODE_TYPE || config .nodeType === DB_TABLE_NODE_TYPE ,
180
212
)
@@ -255,7 +287,7 @@ function formatText(params: ICellRendererParams) {
255
287
256
288
const createRowsForTable = (data : unknown [][], shift : number , isSSrm : boolean ) => {
257
289
const rows = data && data .length > 0 ? (data [0 ]?.length ?? 0 ) : 0
258
- const getIndexInfo = (i : number ) => {
290
+ const getIndexInfo = (i : number ) => {
259
291
return isSSrm ? data ?.[0 ]?.[i ] : i
260
292
}
261
293
return Array .from ({ length: rows }, (_ , i ) => {
@@ -275,7 +307,7 @@ async function getFilterValues(params: SetFilterValuesFuncParams) {
275
307
if (typeof props .data === ' object' && ' header' in props .data ) {
276
308
const index = props .data .header ?.findIndex ((h : string ) => colName === h )
277
309
const server = createServer ()
278
- console .log ({params })
310
+ console .log ({ params })
279
311
const response = await server .getSetFilterValues (index )
280
312
setTimeout (() => {
281
313
if (response .success ) {
@@ -288,26 +320,12 @@ async function getFilterValues(params: SetFilterValuesFuncParams) {
288
320
function createServer() {
289
321
return {
290
322
getSetFilterValues : async (columnIndex ? : number ) => {
291
-
292
- // const { filterColumnIndexList, filterActions, valueList, toValueList } = convertFilterModel(
293
- // request,
294
- // columnHeaders,
295
- // colTypeMap.value
296
- // )
297
323
const response = await config .executeExpression (
298
324
' Standard.Visualization.Table.Visualization' ,
299
325
' get_distinct_values_for_column' ,
300
326
// null as values dont need parsing
301
327
null ,
302
328
` ${columnIndex } ` ,
303
- // send the filter model to get relevant distinct values,
304
- // filterColumnIndexList,
305
- // //column actions i.e Greater Than, Between...
306
- // filterActions,
307
- // //column values, or From Values if using a Between filter
308
- // valueList,
309
- // // To Values (only used in Between filters will be 'Nothing' for any other filter)
310
- // toValueList,
311
329
)
312
330
return {
313
331
success: true ,
@@ -327,15 +345,15 @@ function createServer() {
327
345
const { filterColumnIndexList, filterActions, valueList, toValueList } = convertFilterModel (
328
346
request ,
329
347
columnHeaders ,
330
- colTypeMap .value
348
+ colTypeMap .value ,
331
349
)
332
350
333
351
const response = await config .executeExpression (
334
352
' Standard.Visualization.Table.Visualization' ,
335
353
' get_rows_for_table' ,
336
- // function that will parse filter values to enso compaible
354
+ // function that will parse filter values to enso compaible
337
355
parseArgument ,
338
- // the index of the next bucket of rows to get
356
+ // the index of the next bucket of rows to get
339
357
` ${request .startRow } ` ,
340
358
// column indexes that require a sort
341
359
sortColIndexes ,
@@ -350,7 +368,7 @@ function createServer() {
350
368
// To Values (only used in Between filters will be 'Nothing' for any other filter)
351
369
toValueList ,
352
370
)
353
- console .log ({response })
371
+ console .log ({ response })
354
372
return {
355
373
success: true ,
356
374
data: response .value .rows ,
@@ -675,6 +693,7 @@ watchEffect(() => {
675
693
columnDefs .value .push (toField (i .toString ()))
676
694
}
677
695
rowData .value = addRowIndex (data_ .json )
696
+ isTruncated .value = data_ .all_rows_count !== data_ .json .length
678
697
} else if (data_ .type === ' Object_Matrix' ) {
679
698
columnDefs .value = [
680
699
toLinkField (INDEX_FIELD_NAME , {
@@ -695,6 +714,7 @@ watchEffect(() => {
695
714
}
696
715
}
697
716
rowData .value = addRowIndex (data_ .json )
717
+ isTruncated .value = data_ .all_rows_count !== data_ .json .length
698
718
} else if (data_ .type === ' Excel_Workbook' ) {
699
719
columnDefs .value = [
700
720
toLinkField (' Value' , {
@@ -714,6 +734,7 @@ watchEffect(() => {
714
734
toField (' Value' ),
715
735
]
716
736
rowData .value = data_ .json .map ((row , i ) => ({ [INDEX_FIELD_NAME ]: i , Value: toRender (row ) }))
737
+ isTruncated .value = data_ .all_rows_count ? data_ .all_rows_count !== data_ .json .length : false
717
738
} else if (data_ .json !== undefined ) {
718
739
columnDefs .value =
719
740
data_ .links ?
@@ -750,7 +771,7 @@ watchEffect(() => {
750
771
}) ?? []
751
772
752
773
columnDefs .value =
753
- data_ .has_index_col ?
774
+ data_ .has_index_col ?
754
775
[
755
776
toLinkField (INDEX_FIELD_NAME , {
756
777
tooltipValue: data_ .child_label ,
@@ -761,8 +782,17 @@ watchEffect(() => {
761
782
]
762
783
: dataHeader
763
784
if (! data_ .is_ssrm ) {
764
- const shift = data_ .is_ssrm ? 1 : 0
765
- rowData .value = data_ .data ? createRowsForTable (data_ .data , shift , data_ .is_ssrm ) : []
785
+ rowData .value = data_ .data ? createRowsForTable (data_ .data , 0 , data_ .is_ssrm ) : []
786
+
787
+ // Update paging
788
+ const newRowCount = data_ .all_rows_count == null ? 1 : data_ .all_rows_count
789
+ showRowCount .value = ! (data_ .all_rows_count == null )
790
+ rowCount .value = newRowCount
791
+ const newPageLimit = Math .ceil (newRowCount / rowLimit .value )
792
+ pageLimit .value = newPageLimit
793
+ if (page .value > newPageLimit ) {
794
+ page .value = newPageLimit
795
+ }
766
796
}
767
797
}
768
798
})
@@ -868,6 +898,13 @@ function checkSortAndFilter(e: SortChangedEvent) {
868
898
}
869
899
}
870
900
901
+ // ===============
902
+ // === Updates ===
903
+ // ===============
904
+ onMounted (() => {
905
+ setRowLimit (1000 )
906
+ })
907
+
871
908
// ===============
872
909
// === Toolbar ===
873
910
// ===============
@@ -887,6 +924,30 @@ config.setToolbar(
887
924
888
925
<template >
889
926
<div ref =" rootNode" class =" TableVisualization" @wheel.stop @pointerdown.stop >
927
+ <template v-if =" ! isSSRM " >
928
+ <div class =" table-visualization-status-bar" >
929
+ <select
930
+ v-if =" isRowCountSelectorVisible"
931
+ @change =" setRowLimit(Number(($event.target as HTMLOptionElement).value))"
932
+ >
933
+ <option
934
+ v-for =" limit in selectableRowLimits"
935
+ :key =" limit"
936
+ :value =" limit"
937
+ v-text =" limit"
938
+ ></option >
939
+ </select >
940
+ <template v-if =" showRowCount " >
941
+ <span
942
+ v-if =" isRowCountSelectorVisible && isTruncated"
943
+ v-text =" ` of ${rowCount} rows (Sorting/Filtering disabled).`"
944
+ ></span >
945
+ <span v-else-if =" isRowCountSelectorVisible" v-text =" ' rows.'" ></span >
946
+ <span v-else-if =" rowCount === 1" v-text =" '1 row.'" ></span >
947
+ <span v-else v-text =" `${rowCount} rows.`" ></span >
948
+ </template >
949
+ </div >
950
+ </template >
890
951
<!-- TODO[ao]: Suspence in theory is not needed here (the entire visualization is inside
891
952
suspense), but for some reason it causes reactivity loop - see https://github.com/enso-org/enso/issues/10782 -->
892
953
<Suspense >
0 commit comments