@skydive-project/skydive-ui
Version:
Skydive WebUI v2
248 lines (199 loc) • 6.72 kB
text/typescript
/*
* Copyright (C) 2019 Sylvain Afchain
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import { GoogleChartWrapperChartType } from 'react-google-charts/dist/types'
export interface Graph {
type: GoogleChartWrapperChartType
data: Array<Array<any>>
}
export interface Column {
name: string
options: {
filterList: Array<any>
display: string
}
}
interface Row {
entries: Map<string, any>
details: any
}
export class Result {
private _columns: Array<Column>
private _rows: Array<Row>
graph?: Graph
private colIndexes: Map<string, number>
constructor() {
this._columns = new Array<Column>()
this._rows = new Array<Row>()
this.colIndexes = new Map<string, number>()
}
addColumn(name: string) {
let index = this.colIndexes.get(name)
if (index === undefined) {
this.colIndexes.set(name, this._columns.length)
this._columns.push({ "name": name, options: { filterList: new Array<any>(), display: 'true' } })
}
}
columnIndex(name: string): number | undefined {
return this.colIndexes.get(name)
}
newRow(): Row {
return { entries: new Map<string, any>(), details: null }
}
addRow(row: Row) {
if (row.entries.size) {
for (let key of row.entries.keys()) {
this.addColumn(key)
}
this._rows.push(row)
}
}
// sort only if the format in key-value
sortRowsByKeys(keys: Array<string>) {
if (this._columns.length === 2 && this._columns[0].name === "Key") {
this._rows = this._rows.sort((a, b) => {
var ka = a.entries.get("Key"), kb = b.entries.get("Key")
var ia = keys.indexOf(ka), ib = keys.indexOf(kb)
if (ia === ib) return ka.localeCompare(kb) // -1 == -1
if (ia === -1) return 1
if (ib === -1) return -1
return ia - ib
})
}
}
get rows(): Array<Array<any>> {
var rows = new Array<Array<any>>()
for (let row of this._rows) {
let plain = new Array<any>()
for (let i = 0; i != this.colIndexes.size; i++) {
plain[i] = ""
}
row.entries.forEach((value, key) => {
var index = this.columnIndex(key)
if (index === undefined) {
return
}
plain[index] = value
})
rows.push(plain)
}
return rows
}
get details(): Map<number, any> {
var details = new Map<number, any>()
this._rows.forEach((row, index) => {
if (row.details) {
details.set(index, row.details)
}
})
return details
}
get columns(): Array<Column> {
return this._columns
}
}
export class DataNormalizer {
normalizer: ((any) => any) | null
graph: ((any) => Graph) | null
exclude: Array<string> | null
sortKeys: Array<string> | null
constructor(normalizer?: (data: any) => any, graph?: ((data: any) => Graph), exclude?: Array<string>, sortKeys?: Array<string>) {
this.normalizer = normalizer || null
this.graph = graph || null
this.exclude = exclude || []
this.sortKeys = sortKeys || []
}
private normalizeMap(data: any, result: Result) {
for (let attr in data) {
if (this.exclude && this.exclude.includes(attr)) {
continue
}
let row = result.newRow()
let value = data[attr]
switch (typeof value) {
case "object":
row.entries.set("Key", attr)
row.entries.set("Value", "")
row.details = value
break
case "boolean":
row.entries.set("Key", attr)
row.entries.set("Value", value ? "true" : "false")
break
default:
row.entries.set("Key", attr)
row.entries.set("Value", value)
break
}
result.addRow(row)
}
return result
}
private normalizeScalarArray(data: any, result: Result) {
for (let value of data) {
let row = result.newRow()
if (typeof value === "boolean") {
row.entries.set("Value", value ? "true" : "false")
} else {
row.entries.set("Value", value)
}
result.addRow(row)
}
return result
}
private normalizeObjectArray(data: any, result: Result) {
for (let value of data) {
let row = result.newRow()
for (let attr in value) {
var type = typeof value[attr]
if (type === "boolean") {
row.entries.set(attr, value ? "true" : "false")
} if (type === "string" || type === "number") {
row.entries.set(attr, value[attr] === null ? "" : value[attr])
}
}
result.addRow(row)
}
return result
}
private normalizeArray(data: any, result: Result) {
if ((data as Array<any>).some(value => typeof value === "object")) {
return this.normalizeObjectArray(data, result)
}
this.normalizeScalarArray(data, result)
}
private normalizeData(data: any, result: Result) {
if (Array.isArray(data)) {
this.normalizeArray(data, result)
} else if (typeof data === "object") {
this.normalizeMap(data, result)
}
}
normalize(data: any): Result {
var result = new Result()
if (this.graph) {
result.graph = this.graph(data)
}
if (this.normalizer) {
data = this.normalizer(data)
}
this.normalizeData(data, result)
if (this.sortKeys) {
result.sortRowsByKeys(this.sortKeys)
}
return result
}
}