Add icon to indicate value type in table (#10225)

closes #10018

Sends the value type within the json for table visualisation
Header uses a html template to show it's value type to the right of the title
Displays the value type also in a tooltip, this displays the types "display_text"

<img width="392" alt="image" src="https://github.com/enso-org/enso/assets/170310417/0828e6a2-b30f-4ac7-9a8f-46b4a9cfac91">


tooltip:
<img width="498" alt="image" src="https://github.com/enso-org/enso/assets/170310417/f9964f90-9337-42d3-a0ef-3c58f6d74621">
This commit is contained in:
marthasharkey 2024-06-12 10:06:55 +01:00 committed by GitHub
parent 783276ca34
commit 55af1b9ffd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 81 additions and 15 deletions

View File

@ -1,4 +1,5 @@
<script lang="ts">
import icons from '@/assets/icons.svg'
import { useAutoBlur } from '@/util/autoBlur'
import { VisualizationContainer } from '@/util/visualizationBuiltins'
import '@ag-grid-community/styles/ag-grid.css'
@ -34,11 +35,17 @@ interface Error {
all_rows_count?: undefined
}
interface ValueType {
constructor: string
display_text: string
}
interface Matrix {
type: 'Matrix'
column_count: number
all_rows_count: number
json: unknown[][]
value_type: ValueType[]
}
interface ObjectMatrix {
@ -46,6 +53,7 @@ interface ObjectMatrix {
column_count: number
all_rows_count: number
json: object[]
value_type: ValueType[]
}
interface LegacyMatrix {
@ -53,6 +61,7 @@ interface LegacyMatrix {
column_count: number
all_rows_count: number
json: unknown[][]
value_type: ValueType[]
}
interface LegacyObjectMatrix {
@ -60,6 +69,7 @@ interface LegacyObjectMatrix {
column_count: number
all_rows_count: number
json: object[]
value_type: ValueType[]
}
interface UnknownTable {
@ -73,6 +83,7 @@ interface UnknownTable {
indices_header?: string[]
data: unknown[][] | undefined
indices: unknown[][] | undefined
value_type: ValueType[]
}
declare module 'ag-grid-enterprise' {
@ -265,12 +276,49 @@ function isMatrix(data: object): data is LegacyMatrix {
return json.every((d) => d.length === firstLen)
}
function toField(name: string): ColDef {
return { field: name }
function toField(name: string, valueType?: ValueType | null | undefined): ColDef {
const valType = valueType ? valueType.constructor : null
const displayValue = valueType ? valueType.display_text : null
let icon
switch (valType) {
case 'Char':
icon = 'text3'
break
case 'Boolean':
icon = 'check'
break
case 'Integer':
case 'Float':
case 'Decimal':
case 'Byte':
icon = 'math'
break
case 'Date':
case 'Date_Time':
icon = 'calendar'
break
case 'Time':
icon = 'time'
break
case 'Mixed':
icon = 'mixed'
}
const svgTemplate = `<svg viewBox="0 0 16 16" width="16" height="16"> <use xlink:href="${icons}#${icon}"/> </svg>`
const template =
icon ?
`<div style='display:flex; flex-direction:row; justify-content:space-between; width:inherit;'> ${name} ${svgTemplate}</div>`
: `<div>${name}</div>`
return {
field: name,
headerComponentParams: {
template,
},
headerTooltip: displayValue ? displayValue : '',
}
}
function indexField(): ColDef {
return toField(INDEX_FIELD_NAME)
return { field: INDEX_FIELD_NAME }
}
/** Return a human-readable representation of an object. */
@ -290,6 +338,8 @@ watchEffect(() => {
all_rows_count: 1,
data: undefined,
indices: undefined,
// eslint-disable-next-line camelcase
value_type: undefined,
}
const options = agGridOptions.value
if (options.api == null) {
@ -336,7 +386,7 @@ watchEffect(() => {
isTruncated.value = data_.all_rows_count !== data_.json.length
} else if (isObjectMatrix(data_)) {
// Kept to allow visualization from older versions of the backend.
columnDefs = [INDEX_FIELD_NAME, ...Object.keys(data_.json[0]!)].map(toField)
columnDefs = [INDEX_FIELD_NAME, ...Object.keys(data_.json[0]!)].map((v) => toField(v))
rowData = addRowIndex(data_.json)
isTruncated.value = data_.all_rows_count !== data_.json.length
} else if (Array.isArray(data_.json)) {
@ -347,8 +397,15 @@ watchEffect(() => {
columnDefs = [toField('Value')]
rowData = [{ Value: toRender(data_.json) }]
} else {
const indicesHeader = ('indices_header' in data_ ? data_.indices_header : []).map(toField)
const dataHeader = ('header' in data_ ? data_.header : [])?.map(toField) ?? []
const indicesHeader = ('indices_header' in data_ ? data_.indices_header : []).map((v) =>
toField(v),
)
const dataHeader =
('header' in data_ ? data_.header : [])?.map((v, i) => {
const valueType = data_.value_type ? data_.value_type[i] : null
return toField(v, valueType)
}) ?? []
columnDefs = [...indicesHeader, ...dataHeader]
const rows =
data_.data && data_.data.length > 0 ? data_.data[0]?.length ?? 0

View File

@ -445,6 +445,7 @@ type Value_Type
to_js_object : JS_Object
to_js_object self =
constructor_name = Meta.meta self . constructor . name
display_text_value = self . to_display_text
additional_fields = case self of
Value_Type.Integer size ->
[["bits", size.to_integer]]
@ -460,7 +461,7 @@ type Value_Type
[["type_name", type_name]]
_ -> []
JS_Object.from_pairs <|
[["type", "Value_Type"], ["constructor", constructor_name]] + additional_fields
[["type", "Value_Type"], ["constructor", constructor_name], ["display_text", display_text_value]] + additional_fields
## GROUP Standard.Base.Metadata
ICON metadata

View File

@ -155,11 +155,12 @@ make_json_for_table dataframe indices all_rows_count =
get_vector c = Warning.set (c.to_vector.map v-> make_json_for_value v) []
columns = dataframe.columns
header = ["header", columns.map .name]
value_type = ["value_type", columns.map .value_type]
data = ["data", columns.map get_vector]
all_rows = ["all_rows_count", all_rows_count]
ixes = ["indices", indices.map get_vector]
ixes_header = ["indices_header", indices.map .name]
pairs = [header, data, all_rows, ixes, ixes_header, ["type", "Table"]]
pairs = [header, value_type, data, all_rows, ixes, ixes_header, ["type", "Table"]]
JS_Object.from_pairs pairs
## PRIVATE

View File

@ -38,13 +38,14 @@ type Foo
add_specs suite_builder =
make_json header data all_rows ixes_header ixes =
make_json header data all_rows ixes_header ixes value_type =
p_header = ["header", header]
p_data = ["data", data]
p_all_rows = ["all_rows_count", all_rows]
p_ixes = ["indices", ixes]
p_ixes_header = ["indices_header", ixes_header]
pairs = [p_header, p_data, p_all_rows, p_ixes, p_ixes_header, ["type", "Table"]]
p_value_type = ["value_type", value_type]
pairs = [p_header, p_value_type ,p_data, p_all_rows, p_ixes, p_ixes_header, ["type", "Table"]]
JS_Object.from_pairs pairs . to_text
suite_builder.group "Table Visualization" group_builder->
@ -52,27 +53,33 @@ add_specs suite_builder =
group_builder.specify "should visualize database tables" <|
vis = Visualization.prepare_visualization data.t 1
json = make_json header=["A", "B", "C"] data=[['a'], [2], [3]] all_rows=3 ixes_header=[] ixes=[]
value_type_int = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Integer"], ["display_text", "Integer (64 bits)"], ["bits", 64]]
value_type_char = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Char"], ["display_text", "Char (variable length, max_size=unlimited)"], ["size", Nothing], ["variable_length", True]]
json = make_json header=["A", "B", "C"] data=[['a'], [2], [3]] all_rows=3 ixes_header=[] ixes=[] value_type=[value_type_char, value_type_int, value_type_int]
vis . should_equal json
group_builder.specify "should visualize database columns" <|
vis = Visualization.prepare_visualization (data.t.at "A") 2
json = make_json header=["A"] data=[['a', 'a']] all_rows=3 ixes_header=[] ixes=[]
value_type_char = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Char"], ["display_text", "Char (variable length, max_size=unlimited)"], ["size", Nothing], ["variable_length", True]]
value_type_float = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Float"], ["display_text", "Float (64 bits)"], ["bits", 64]]
json = make_json header=["A"] data=[['a', 'a']] all_rows=3 ixes_header=[] ixes=[] value_type=[value_type_char]
vis . should_equal json
g = data.t.aggregate ["A", "B"] [Aggregate_Column.Average "C"] . at "Average C"
vis2 = Visualization.prepare_visualization g 1
json2 = make_json header=["Average C"] data=[[4.0]] all_rows=2 ixes_header=[] ixes=[]
json2 = make_json header=["Average C"] data=[[4.0]] all_rows=2 ixes_header=[] ixes=[] value_type=[value_type_float]
vis2 . should_equal json2
group_builder.specify "should visualize dataframe tables" <|
vis = Visualization.prepare_visualization data.t2 1
json = make_json header=["A", "B", "C"] data=[[1], [4], [7]] all_rows=3 ixes_header=["#"] ixes=[[0]]
value_type_int = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Integer"], ["display_text", "Integer (64 bits)"], ["bits", 64]]
json = make_json header=["A", "B", "C"] data=[[1], [4], [7]] all_rows=3 ixes_header=["#"] ixes=[[0]] value_type=[value_type_int, value_type_int, value_type_int]
vis . should_equal json
group_builder.specify "should visualize dataframe columns" <|
vis = Visualization.prepare_visualization (data.t2.at "A") 2
json = make_json header=["A"] data=[[1, 2]] all_rows=3 ixes_header=["#"] ixes=[[0, 1]]
value_type_int = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Integer"], ["display_text", "Integer (64 bits)"], ["bits", 64]]
json = make_json header=["A"] data=[[1, 2]] all_rows=3 ixes_header=["#"] ixes=[[0, 1]] value_type=[value_type_int]
vis . should_equal json
group_builder.specify "should handle Vectors" <|