Code Monkey home page Code Monkey logo

flat-ui's Introduction

flat-ui

Welcome friends! flat-ui is a React component that will render your flat dataset (an array of objects) in a table view:

screenshot

It will...

  • auto-detect types
  • show a distribution of each quantitative column
  • calculate a diff between the main dataset and a diffData dataset
  • give more information about a hovered row & column
  • allow the user to...
    • filter each column
    • sort by any column
    • sticky any column to the left
    • download the filtered & sorted data (csv or json)
    • cycle through the diffs, scrolling to each changed row

Usage

Install using npm or yarn:

yarn add @githubocto/flat-ui

Basic usage:

import { Grid } from '@githubocto/flat-ui';

const MyComponent = () => {
  const data = [{ column1: 123 }, { column1: 234 }];

  return <Grid data={data} />;
};

Props

data

array

Your dataset, formatted as an array of objects, where each object is a row in the table.

Optional props

diffData

array

A modified version of your main dataset, formatted as an array of objects, where each object is a row in the table. The table will show "differences" between this dataset and the main dataset:

  • added lines
  • removed lines
  • modified cells

metadata

object

column names as keys and descriptions as values.

canDownload

boolean

Whether or not the table provides "download csv" and "download json" buttons.

downloadFilename

string

The name of the downloaded CSV or JSON file (without extension).

defaultFilters

object

column names as keys, with filter values as values:

  • string for text columns
  • array of numbers for quantitative columns (numbers or dates)

The user can interact with the table and update the filters, but the table will use the default filters when defaultFilters or data changes.

defaultSort

array

The name of the column and the order you want the table to initialize sorting by (e.g. ["Location", "desc"]). The user can interact with the table and update the sort, but the table will use the default sort when defaultSort or data changes.

defaultStickyColumnName

string

The name of the column you want the table to initialize stickied to the left. The user can interact with the table and update the sticky column, but the table will use the default sticky column when defaultStickyColumnName or data changes.

onChange

function

A callback function whose first parameter is the grid state:

{
  stickyColumnName: "",
  columnNames: ["", ""],
  filteredData: [{}, {}],
  diffs: [{}, {}], // where __status__ is "new"|"old"|"modified"
  filters: {},
  sort: ["column name", "asc" or "desc"],
  schema: {}, // column names : array|short-array|category|number|date
}

isEditable

boolean

Whether or not to allow the user to edit the table.

onEdit

(newData: any[]) => void

A callback when the user edits the data with the updated dataset. This is intended to be used as a controlled component, where the parent component handles data changes.

Developing locally

To get the example up & running:

yarn
yarn start

and also start the example server:

cd example
yarn
yarn start

flat-ui's People

Contributors

adboomlodestar avatar colmanhumphrey avatar fahad19 avatar lonerifle avatar mattrothenberg avatar vikpe avatar wattenberger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

flat-ui's Issues

Sticky column cells not aligned with other columns

I encountered a few issues that I wanted to share in case useful. I'm currently only playing with the library so not necessary to fix!

In the sandbox, https://codesandbox.io/s/dazzling-cray-bjmjs, hovering the sticky column seems to highlight a different row in the rest of the table.

image

Switching between pinning the first and second column seems to shuffle the contents of the first two column. This might be related to previous item.

I tried using the component inside another tailwind project nested inside a div that also has a group class name which causes hover elements to show up too aggressively. Could call this a usage issue :)

image

Provide options to reduce data row height

Flat UI only displays 9 and a half rows in a fixed 560px table view and each data cell sets 40px height via inline styles.

It would be more aesthetically pleasing to have shorter table data rows in applications with limited viewports, such as VSCode notebooks and their cell outputs.

I was able to overwrite some of those CSS rules, but I can't find how to remove the extra spaces between data rows:

flat-data-grid-ui-shorter-rows

See more info in our data table renderers: RandomFractals/vscode-data-table#138

In general, I think it would be best to remove some of those inline div styles and add more custom classes for the table rows and cells.

XSS vulnerability in string cells and long value previews

Both string cells and long value previews inject stringWithLinks via dangerouslySetInnerHTML. However stringWithLinks is created by passing raw input through anchorme, which doesn't sanitize HTML as per alexcorvi/anchorme.js#54 .

Repro: https://flatgithub.com/danzvara/csv-xss?filename=kokos.csv&sha=9caf159937ecb7a87bd896da2e70e4e86ef3da1e

I would suggest sandboxing the string outputs in an iframe (or perhaps choosing a sanitization library to make stringWithLinks safe).

Show number of columns in the summary row

Latest version of this data grid displays the number of data rows in a grid footer.

I think it would be valuable to see the number of columns there too, similar to how most data frame libraries display them now.

Example of df.head table display:

kaggle-df-head

Also, I was able to integrate it into VSCode Data Table renders extension and plan to ship that update soon.

I hope this addition will improve datasets preview in VSCode Jupyter notebooks. Example:

world-rivers-flat-data-grid-renderer-view

Extension: https://marketplace.visualstudio.com/items?itemName=RandomFractalsInc.vscode-data-table

Scoping CSS on Import (Tailwind apply?)

Hey all,

Really fantastic package you have!

I recently tried to use this package, and faced one small issue: the tailwind applys from index.css also applied to our whole site. The one I noticed most was body { @apply bg-gray-200;}, because we have no default background color set on the site. Of course this particular one was an easy fix, but the rest are maybe less obvious.

Is there a way to avoid this or an easy way to mitigate?

I'm not very advanced at CSS or Tailwind, so perhaps there's a trivial way to do this - if so, apologies for the hassle!

Support Apache Arrow tables

Apache Arrow support a row iterator but not .map. It would be great if you could add explicit support for Apache Arrow as an efficient format for tabular data.

Here is a small example that doesn't work right now.

const int32_vector = arrow.Int32Vector.from([1,2,3]);
const my_table = arrow.Table.new(
  arrow.Column.new('column', int32_vector))

export default function App() {
  return <Grid data={my_table} />;
}

Multiselect on categories

It would be great if you could multiselect values on category fields. Currently you can only select one category to filter on.

Any interest in this? I don't mind taking a crack at it.

defaultStickyColumnName prop not working

Thanks for this awesome library! I noticed that defaultStickyColumnName was not being respected when testing it out.

Here's a codesandbox repro https://codesandbox.io/s/dazzling-cray-bjmjs

It seems like columnNames is updated after handleStickyColumnNameChange

React.useEffect(() => {
if (props.defaultStickyColumnName)
handleStickyColumnNameChange(props.defaultStickyColumnName);
}, [props.defaultStickyColumnName, props.data]);

React.useEffect(updateColumnNames, [props.data, stickyColumnName]);

which causes the issue in this logic

flat-ui/src/store.ts

Lines 86 to 90 in 07b88ec

handleStickyColumnNameChange: (columnName) =>
set((draft) => {
if (!draft.columnNames.includes(columnName)) return;
draft.stickyColumnName = columnName;
}),

numeric strings in "id" field are coerced into numbers, then ignored for diffs despite uniqueness

When calculating diffs, handleDiffDataChange() in src/store would identify a field whose number of unique values is equal to the number of data fields. The id field is assumed to be one such column... if its sort value type is a string:

if (columnName.toLowerCase() === 'id' && isString) return true;

This does not work so well when used in tandem with handleDataChange(), which generates a schema, and would coerce numeric strings into numbers. For id fields whose values are numeric strings, each identifier gets coerced into a number, which then gets ignored by handleDiffDataChange() based on the abovementioned criterion.

Because the most unique column is used as a key in diffDataMap, this in turn influences how diffs are generated.

An example of this can be found here. As id is a numeric string, the contact field is used instead, but since contact is an object type, it serves as a poor key for diffDataMap, resulting in the diffs being inaccurate in the grid.

This issue hence proposes that the id field is simply assumed to be an unique column regardless of its sort value type, or at least, if its sort value type is a string or a number. Alternatively, generateSchema() could be modified such that the data type for id remains unchanged.

CSS Injection Vulnerability

When using the DOMPurify library to sanitize HTML from malicious code here, the library doesn't sanitize CSS style tags. These can be used to change the website's appearance and possibly to pull off clickjacking attacks. - https://portswigger.net/web-security/clickjacking

PoC: https://flatgithub.com/makuga01/csv-test?filename=css.csv&sha=9cfecff99206e7a11716d14b48a2edb9c16ce0c1

I suggest adding using a DOMPurify config like this one:

const dompurifyConfig = {
  FORBID_TAGS: ['style', 'form'],
}
const sanitized = DOMPurify.sanitize(displayValue, dompurifyConfig);

I also added HTML forms to the forbidden tags as they can be used for creating a fake login screen

Header (column names + histograms) aren't sticky Safari

E.g. using this example data: https://flatgithub.com/the-pudding/data?filename=boybands%2Fboys.csv&sha=9b4e89ed178e11bf70a9b3d8ffa57ac2ea181b96

In Firefox and Chrome, this works well: the body scrolls while the header stays in place:

CleanShot.2021-08-23.at.09.57.59.mp4

However in Safari, the header scrolls away too:

CleanShot.2021-08-23.at.09.59.24.mp4

I seem to recall having a somewhat similar issue previously with my own code, with flex acting differently in Safari, however the details don't come directly to mind. I can try at least to have a quick look to see what's causing it here!

I'm on macOS Big Sur 11.3.1, Safari 14.1.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.