Merge pull request #1103 from datopian/feat/portaljs-components-improvements
Components API and docs improvements Related to: #1089
This commit is contained in:
commit
38dd7103a3
5
.changeset/rotten-chefs-shout.md
Normal file
5
.changeset/rotten-chefs-shout.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
'@portaljs/components': major
|
||||
---
|
||||
|
||||
Components API tidying up and storybook docs improvements.
|
||||
@ -7,7 +7,12 @@ export function Catalog({
|
||||
datasets,
|
||||
facets,
|
||||
}: {
|
||||
datasets: any[];
|
||||
datasets: {
|
||||
_id: string | number;
|
||||
metadata: { title: string; [k: string]: string | number };
|
||||
url_path: string;
|
||||
[k: string]: any;
|
||||
}[];
|
||||
facets: string[];
|
||||
}) {
|
||||
const [indexFilter, setIndexFilter] = useState('');
|
||||
@ -56,7 +61,7 @@ export function Catalog({
|
||||
//Then check if the selectedValue for the given facet is included in the dataset metadata
|
||||
.filter((dataset) => {
|
||||
//Avoids a server rendering breakage
|
||||
if (!watch() || Object.keys(watch()).length === 0) return true
|
||||
if (!watch() || Object.keys(watch()).length === 0) return true;
|
||||
//This will filter only the key pairs of the metadata values that were selected as facets
|
||||
const datasetFacets = Object.entries(dataset.metadata).filter((entry) =>
|
||||
facets.includes(entry[0])
|
||||
@ -86,9 +91,7 @@ export function Catalog({
|
||||
className="p-2 ml-1 text-sm shadow border border-block"
|
||||
{...register(elem[0] + '.selectedValue')}
|
||||
>
|
||||
<option value="">
|
||||
Filter by {elem[0]}
|
||||
</option>
|
||||
<option value="">Filter by {elem[0]}</option>
|
||||
{(elem[1] as { possibleValues: string[] }).possibleValues.map(
|
||||
(val) => (
|
||||
<option
|
||||
@ -102,10 +105,10 @@ export function Catalog({
|
||||
)}
|
||||
</select>
|
||||
))}
|
||||
<ul className='mb-5 pl-6 mt-5 list-disc'>
|
||||
<ul className="mb-5 pl-6 mt-5 list-disc">
|
||||
{filteredDatasets.map((dataset) => (
|
||||
<li className='py-2' key={dataset._id}>
|
||||
<a className='font-medium underline' href={dataset.url_path}>
|
||||
<li className="py-2" key={dataset._id}>
|
||||
<a className="font-medium underline" href={dataset.url_path}>
|
||||
{dataset.metadata.title
|
||||
? dataset.metadata.title
|
||||
: dataset.url_path}
|
||||
@ -116,4 +119,3 @@ export function Catalog({
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -4,12 +4,14 @@ import { read, utils } from 'xlsx';
|
||||
import { AgGridReact } from 'ag-grid-react';
|
||||
import 'ag-grid-community/styles/ag-grid.css';
|
||||
import 'ag-grid-community/styles/ag-theme-alpine.css';
|
||||
import { Data } from '../types/properties';
|
||||
|
||||
export type ExcelProps = {
|
||||
url: string;
|
||||
data: Required<Pick<Data, 'url'>>;
|
||||
};
|
||||
|
||||
export function Excel({ url }: ExcelProps) {
|
||||
export function Excel({ data }: ExcelProps) {
|
||||
const url = data.url;
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [activeSheetName, setActiveSheetName] = useState<string>();
|
||||
const [workbook, setWorkbook] = useState<any>();
|
||||
|
||||
@ -2,6 +2,7 @@ import { QueryClient, QueryClientProvider, useQuery } from 'react-query';
|
||||
import Papa from 'papaparse';
|
||||
import { Grid } from '@githubocto/flat-ui';
|
||||
import LoadingSpinner from './LoadingSpinner';
|
||||
import { Data } from '../types/properties';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
@ -36,30 +37,25 @@ export async function parseCsv(file: string, parsingConfig): Promise<any> {
|
||||
}
|
||||
|
||||
export interface FlatUiTableProps {
|
||||
url?: string;
|
||||
data?: { [key: string]: number | string }[];
|
||||
rawCsv?: string;
|
||||
randomId?: number;
|
||||
data: Data;
|
||||
uniqueId?: number;
|
||||
bytes: number;
|
||||
parsingConfig: any;
|
||||
}
|
||||
export const FlatUiTable: React.FC<FlatUiTableProps> = ({
|
||||
url,
|
||||
data,
|
||||
rawCsv,
|
||||
uniqueId,
|
||||
bytes = 5132288,
|
||||
parsingConfig = {},
|
||||
}) => {
|
||||
const randomId = Math.random();
|
||||
uniqueId = uniqueId ?? Math.random();
|
||||
return (
|
||||
// Provide the client to your App
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TableInner
|
||||
bytes={bytes}
|
||||
url={url}
|
||||
data={data}
|
||||
rawCsv={rawCsv}
|
||||
randomId={randomId}
|
||||
uniqueId={uniqueId}
|
||||
parsingConfig={parsingConfig}
|
||||
/>
|
||||
</QueryClientProvider>
|
||||
@ -67,33 +63,32 @@ export const FlatUiTable: React.FC<FlatUiTableProps> = ({
|
||||
};
|
||||
|
||||
const TableInner: React.FC<FlatUiTableProps> = ({
|
||||
url,
|
||||
data,
|
||||
rawCsv,
|
||||
randomId,
|
||||
uniqueId,
|
||||
bytes,
|
||||
parsingConfig,
|
||||
}) => {
|
||||
if (data) {
|
||||
const url = data.url;
|
||||
const csv = data.csv;
|
||||
const values = data.values;
|
||||
|
||||
if (values) {
|
||||
return (
|
||||
<div className="w-full" style={{ height: '500px' }}>
|
||||
<Grid data={data} />
|
||||
<Grid data={values} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const { data: csvString, isLoading: isDownloadingCSV } = useQuery(
|
||||
['dataCsv', url, randomId],
|
||||
['dataCsv', url, uniqueId],
|
||||
() => getCsv(url as string, bytes),
|
||||
{ enabled: !!url }
|
||||
);
|
||||
const { data: parsedData, isLoading: isParsing } = useQuery(
|
||||
['dataPreview', csvString, randomId],
|
||||
['dataPreview', csvString, uniqueId],
|
||||
() =>
|
||||
parseCsv(
|
||||
rawCsv ? (rawCsv as string) : (csvString as string),
|
||||
parsingConfig
|
||||
),
|
||||
{ enabled: rawCsv ? true : !!csvString }
|
||||
parseCsv(csv ? (csv as string) : (csvString as string), parsingConfig),
|
||||
{ enabled: csv ? true : !!csvString }
|
||||
);
|
||||
if (isParsing || isDownloadingCSV)
|
||||
<div className="w-full flex justify-center items-center h-[500px]">
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
import { CSSProperties } from "react";
|
||||
import { CSSProperties } from 'react';
|
||||
import { Data } from '../types/properties';
|
||||
|
||||
export interface IframeProps {
|
||||
url: string;
|
||||
data: Required<Pick<Data, 'url'>>;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
export function Iframe({
|
||||
url, style
|
||||
}: IframeProps) {
|
||||
export function Iframe({ data, style }: IframeProps) {
|
||||
const url = data.url;
|
||||
return (
|
||||
<iframe src={url} style={style ?? { width: `100%`, height: `100%` }}></iframe>
|
||||
<iframe
|
||||
src={url}
|
||||
style={style ?? { width: `100%`, height: `100%` }}
|
||||
></iframe>
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,31 +2,33 @@ import { useEffect, useState } from 'react';
|
||||
import LoadingSpinner from './LoadingSpinner';
|
||||
import { VegaLite } from './VegaLite';
|
||||
import loadData from '../lib/loadData';
|
||||
import { Data } from '../types/properties';
|
||||
|
||||
type AxisType = 'quantitative' | 'temporal';
|
||||
type TimeUnit = 'year' | undefined; // or ...
|
||||
|
||||
export type LineChartProps = {
|
||||
data: Array<Array<string | number>> | string | { x: string; y: number }[];
|
||||
data: Omit<Data, 'csv'>;
|
||||
title?: string;
|
||||
xAxis?: string;
|
||||
xAxis: string;
|
||||
xAxisType?: AxisType;
|
||||
xAxisTimeUnit: TimeUnit;
|
||||
yAxis?: string;
|
||||
xAxisTimeUnit?: TimeUnit;
|
||||
yAxis: string;
|
||||
yAxisType?: AxisType;
|
||||
fullWidth?: boolean;
|
||||
};
|
||||
|
||||
export function LineChart({
|
||||
data = [],
|
||||
fullWidth = false,
|
||||
data,
|
||||
title = '',
|
||||
xAxis = 'x',
|
||||
xAxis,
|
||||
xAxisType = 'temporal',
|
||||
xAxisTimeUnit = 'year', // TODO: defaults to undefined would probably work better... keeping it as it's for compatibility purposes
|
||||
yAxis = 'y',
|
||||
yAxis,
|
||||
yAxisType = 'quantitative',
|
||||
}: LineChartProps) {
|
||||
const url = data.url;
|
||||
const values = data.values;
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
// By default, assumes data is an Array...
|
||||
@ -64,13 +66,12 @@ export function LineChart({
|
||||
} as any;
|
||||
|
||||
useEffect(() => {
|
||||
// If data is string, assume it's a URL
|
||||
if (typeof data === 'string') {
|
||||
if (url) {
|
||||
setIsLoading(true);
|
||||
|
||||
// Manualy loading the data allows us to do other kinds
|
||||
// of stuff later e.g. load a file partially
|
||||
loadData(data).then((res: any) => {
|
||||
loadData(url).then((res: any) => {
|
||||
setSpecData({ values: res, format: { type: 'csv' } });
|
||||
setIsLoading(false);
|
||||
});
|
||||
@ -78,12 +79,8 @@ export function LineChart({
|
||||
}, []);
|
||||
|
||||
var vegaData = {};
|
||||
if (Array.isArray(data)) {
|
||||
var dataObj;
|
||||
dataObj = data.map((r) => {
|
||||
return { x: r[0], y: r[1] };
|
||||
});
|
||||
vegaData = { table: dataObj };
|
||||
if (values) {
|
||||
vegaData = { table: values };
|
||||
}
|
||||
|
||||
return isLoading ? (
|
||||
@ -91,6 +88,6 @@ export function LineChart({
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
) : (
|
||||
<VegaLite fullWidth={fullWidth} data={vegaData} spec={spec} />
|
||||
<VegaLite data={vegaData} spec={spec} />
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import { CSSProperties, useEffect, useState } from 'react';
|
||||
import LoadingSpinner from './LoadingSpinner';
|
||||
import loadData from '../lib/loadData';
|
||||
import chroma from 'chroma-js';
|
||||
import { GeospatialData } from '../types/properties';
|
||||
import {
|
||||
MapContainer,
|
||||
TileLayer,
|
||||
@ -14,26 +15,25 @@ import * as L from 'leaflet';
|
||||
|
||||
export type MapProps = {
|
||||
layers: {
|
||||
data: string | GeoJSON.GeoJSON;
|
||||
data: GeospatialData;
|
||||
name: string;
|
||||
colorScale?: {
|
||||
starting: string;
|
||||
ending: string;
|
||||
};
|
||||
tooltip?:
|
||||
| {
|
||||
propNames: string[];
|
||||
}
|
||||
| boolean;
|
||||
_id?: number;
|
||||
| {
|
||||
propNames: string[];
|
||||
}
|
||||
| boolean;
|
||||
}[];
|
||||
title?: string;
|
||||
center?: { latitude: number | undefined; longitude: number | undefined };
|
||||
zoom?: number;
|
||||
style?: CSSProperties;
|
||||
autoZoomConfiguration?: {
|
||||
layerName: string
|
||||
}
|
||||
layerName: string;
|
||||
};
|
||||
};
|
||||
|
||||
export function Map({
|
||||
@ -56,17 +56,19 @@ export function Map({
|
||||
|
||||
useEffect(() => {
|
||||
const loadDataPromises = layers.map(async (layer) => {
|
||||
const url = layer.data.url;
|
||||
const geojson = layer.data.geojson;
|
||||
let layerData: any;
|
||||
|
||||
if (typeof layer.data === 'string') {
|
||||
if (url) {
|
||||
// If "data" is string, assume it's a URL
|
||||
setIsLoading(true);
|
||||
layerData = await loadData(layer.data).then((res: any) => {
|
||||
layerData = await loadData(url).then((res: any) => {
|
||||
return JSON.parse(res);
|
||||
});
|
||||
} else {
|
||||
// Else, expect raw GeoJSON
|
||||
layerData = layer.data;
|
||||
layerData = geojson;
|
||||
}
|
||||
|
||||
if (layer.colorScale) {
|
||||
@ -111,23 +113,23 @@ export function Map({
|
||||
// Create the title box
|
||||
var info = new L.Control() as any;
|
||||
|
||||
info.onAdd = function() {
|
||||
info.onAdd = function () {
|
||||
this._div = L.DomUtil.create('div', 'info');
|
||||
this.update();
|
||||
return this._div;
|
||||
};
|
||||
|
||||
info.update = function() {
|
||||
info.update = function () {
|
||||
this._div.innerHTML = `<h4 style="font-weight: 600; background: #f9f9f9; padding: 5px; border-radius: 5px; color: #464646;">${title}</h4>`;
|
||||
};
|
||||
|
||||
if (title) info.addTo(map.target);
|
||||
if(!autoZoomConfiguration) return;
|
||||
if (!autoZoomConfiguration) return;
|
||||
|
||||
let layerToZoomBounds = L.latLngBounds(L.latLng(0, 0), L.latLng(0, 0));
|
||||
|
||||
layers.forEach((layer) => {
|
||||
if(layer.name === autoZoomConfiguration.layerName) {
|
||||
if (layer.name === autoZoomConfiguration.layerName) {
|
||||
const data = layersData.find(
|
||||
(layerData) => layerData.name === layer.name
|
||||
)?.data;
|
||||
|
||||
@ -1,22 +1,24 @@
|
||||
// Core viewer
|
||||
import { Viewer, Worker, SpecialZoomLevel } from '@react-pdf-viewer/core';
|
||||
import { defaultLayoutPlugin } from '@react-pdf-viewer/default-layout';
|
||||
import { Data } from '../types/properties';
|
||||
|
||||
// Import styles
|
||||
import '@react-pdf-viewer/core/lib/styles/index.css';
|
||||
import '@react-pdf-viewer/default-layout/lib/styles/index.css';
|
||||
|
||||
export interface PdfViewerProps {
|
||||
url: string;
|
||||
data: Required<Pick<Data, 'url'>>;
|
||||
layout: boolean;
|
||||
parentClassName?: string;
|
||||
}
|
||||
|
||||
export function PdfViewer({
|
||||
url,
|
||||
data,
|
||||
layout = false,
|
||||
parentClassName,
|
||||
parentClassName = 'h-screen',
|
||||
}: PdfViewerProps) {
|
||||
const url = data.url;
|
||||
const defaultLayoutPluginInstance = defaultLayoutPlugin();
|
||||
return (
|
||||
<Worker workerUrl="https://unpkg.com/pdfjs-dist@2.15.349/build/pdf.worker.js">
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { QueryClient, QueryClientProvider, useQuery } from "react-query";
|
||||
import { Plotly } from "./Plotly";
|
||||
import Papa, { ParseConfig } from "papaparse";
|
||||
import LoadingSpinner from "./LoadingSpinner";
|
||||
import { QueryClient, QueryClientProvider, useQuery } from 'react-query';
|
||||
import { Plotly } from './Plotly';
|
||||
import Papa, { ParseConfig } from 'papaparse';
|
||||
import LoadingSpinner from './LoadingSpinner';
|
||||
import { Data } from '../types/properties';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
@ -17,7 +18,7 @@ async function getCsv(url: string, bytes: number) {
|
||||
|
||||
async function parseCsv(
|
||||
file: string,
|
||||
parsingConfig: ParseConfig,
|
||||
parsingConfig: ParseConfig
|
||||
): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
Papa.parse(file, {
|
||||
@ -39,43 +40,40 @@ async function parseCsv(
|
||||
}
|
||||
|
||||
export interface PlotlyBarChartProps {
|
||||
url?: string;
|
||||
data?: { [key: string]: number | string }[];
|
||||
rawCsv?: string;
|
||||
randomId?: number;
|
||||
data: Data;
|
||||
uniqueId?: number;
|
||||
bytes?: number;
|
||||
parsingConfig?: ParseConfig;
|
||||
xAxis: string;
|
||||
yAxis: string;
|
||||
lineLabel?: string;
|
||||
// TODO: commented out because this doesn't work. I believe
|
||||
// this would only make any difference on charts with multiple
|
||||
// traces.
|
||||
// lineLabel?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export const PlotlyBarChart: React.FC<PlotlyBarChartProps> = ({
|
||||
url,
|
||||
data,
|
||||
rawCsv,
|
||||
bytes = 5132288,
|
||||
parsingConfig = {},
|
||||
xAxis,
|
||||
yAxis,
|
||||
lineLabel,
|
||||
title = "",
|
||||
// lineLabel,
|
||||
title = '',
|
||||
}) => {
|
||||
const randomId = Math.random();
|
||||
const uniqueId = Math.random();
|
||||
return (
|
||||
// Provide the client to your App
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<PlotlyBarChartInner
|
||||
url={url}
|
||||
data={data}
|
||||
rawCsv={rawCsv}
|
||||
randomId={randomId}
|
||||
uniqueId={uniqueId}
|
||||
bytes={bytes}
|
||||
parsingConfig={parsingConfig}
|
||||
xAxis={xAxis}
|
||||
yAxis={yAxis}
|
||||
lineLabel={lineLabel ?? yAxis}
|
||||
// lineLabel={lineLabel ?? yAxis}
|
||||
title={title}
|
||||
/>
|
||||
</QueryClientProvider>
|
||||
@ -83,30 +81,28 @@ export const PlotlyBarChart: React.FC<PlotlyBarChartProps> = ({
|
||||
};
|
||||
|
||||
const PlotlyBarChartInner: React.FC<PlotlyBarChartProps> = ({
|
||||
url,
|
||||
data,
|
||||
rawCsv,
|
||||
randomId,
|
||||
uniqueId,
|
||||
bytes,
|
||||
parsingConfig,
|
||||
xAxis,
|
||||
yAxis,
|
||||
lineLabel,
|
||||
// lineLabel,
|
||||
title,
|
||||
}) => {
|
||||
if (data) {
|
||||
if (data.values) {
|
||||
return (
|
||||
<div className="w-full" style={{ height: "500px" }}>
|
||||
<div className="w-full" style={{ height: '500px' }}>
|
||||
<Plotly
|
||||
layout={{
|
||||
title,
|
||||
}}
|
||||
data={[
|
||||
{
|
||||
x: data.map((d) => d[xAxis]),
|
||||
y: data.map((d) => d[yAxis]),
|
||||
type: "bar",
|
||||
name: lineLabel,
|
||||
x: data.values.map((d) => d[xAxis]),
|
||||
y: data.values.map((d) => d[yAxis]),
|
||||
type: 'bar',
|
||||
// name: lineLabel,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
@ -114,18 +110,18 @@ const PlotlyBarChartInner: React.FC<PlotlyBarChartProps> = ({
|
||||
);
|
||||
}
|
||||
const { data: csvString, isLoading: isDownloadingCSV } = useQuery(
|
||||
["dataCsv", url, randomId],
|
||||
() => getCsv(url as string, bytes ?? 5132288),
|
||||
{ enabled: !!url },
|
||||
['dataCsv', data.url, uniqueId],
|
||||
() => getCsv(data.url as string, bytes ?? 5132288),
|
||||
{ enabled: !!data.url }
|
||||
);
|
||||
const { data: parsedData, isLoading: isParsing } = useQuery(
|
||||
["dataPreview", csvString, randomId],
|
||||
['dataPreview', csvString, uniqueId],
|
||||
() =>
|
||||
parseCsv(
|
||||
rawCsv ? (rawCsv as string) : (csvString as string),
|
||||
parsingConfig ?? {},
|
||||
data.csv ? (data.csv as string) : (csvString as string),
|
||||
parsingConfig ?? {}
|
||||
),
|
||||
{ enabled: rawCsv ? true : !!csvString },
|
||||
{ enabled: data.csv ? true : !!csvString }
|
||||
);
|
||||
if (isParsing || isDownloadingCSV)
|
||||
<div className="w-full flex justify-center items-center h-[500px]">
|
||||
@ -133,7 +129,7 @@ const PlotlyBarChartInner: React.FC<PlotlyBarChartProps> = ({
|
||||
</div>;
|
||||
if (parsedData)
|
||||
return (
|
||||
<div className="w-full" style={{ height: "500px" }}>
|
||||
<div className="w-full" style={{ height: '500px' }}>
|
||||
<Plotly
|
||||
layout={{
|
||||
title,
|
||||
@ -142,8 +138,8 @@ const PlotlyBarChartInner: React.FC<PlotlyBarChartProps> = ({
|
||||
{
|
||||
x: parsedData.data.map((d: any) => d[xAxis]),
|
||||
y: parsedData.data.map((d: any) => d[yAxis]),
|
||||
type: "bar",
|
||||
name: lineLabel,
|
||||
type: 'bar',
|
||||
// name: lineLabel, TODO: commented out because this doesn't work
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { QueryClient, QueryClientProvider, useQuery } from "react-query";
|
||||
import { Plotly } from "./Plotly";
|
||||
import Papa, { ParseConfig } from "papaparse";
|
||||
import LoadingSpinner from "./LoadingSpinner";
|
||||
import { QueryClient, QueryClientProvider, useQuery } from 'react-query';
|
||||
import { Plotly } from './Plotly';
|
||||
import Papa, { ParseConfig } from 'papaparse';
|
||||
import LoadingSpinner from './LoadingSpinner';
|
||||
import { Data } from '../types/properties';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
@ -17,7 +18,7 @@ async function getCsv(url: string, bytes: number) {
|
||||
|
||||
async function parseCsv(
|
||||
file: string,
|
||||
parsingConfig: ParseConfig,
|
||||
parsingConfig: ParseConfig
|
||||
): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
Papa.parse(file, {
|
||||
@ -39,38 +40,33 @@ async function parseCsv(
|
||||
}
|
||||
|
||||
export interface PlotlyLineChartProps {
|
||||
url?: string;
|
||||
data?: { [key: string]: number | string }[];
|
||||
rawCsv?: string;
|
||||
randomId?: number;
|
||||
data: Data;
|
||||
bytes?: number;
|
||||
parsingConfig?: ParseConfig;
|
||||
xAxis: string;
|
||||
yAxis: string;
|
||||
lineLabel?: string;
|
||||
title?: string;
|
||||
uniqueId?: number;
|
||||
}
|
||||
|
||||
export const PlotlyLineChart: React.FC<PlotlyLineChartProps> = ({
|
||||
url,
|
||||
data,
|
||||
rawCsv,
|
||||
bytes = 5132288,
|
||||
parsingConfig = {},
|
||||
xAxis,
|
||||
yAxis,
|
||||
lineLabel,
|
||||
title = "",
|
||||
title = '',
|
||||
uniqueId,
|
||||
}) => {
|
||||
const randomId = Math.random();
|
||||
uniqueId = uniqueId ?? Math.random();
|
||||
return (
|
||||
// Provide the client to your App
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<LineChartInner
|
||||
url={url}
|
||||
data={data}
|
||||
rawCsv={rawCsv}
|
||||
randomId={randomId}
|
||||
uniqueId={uniqueId}
|
||||
bytes={bytes}
|
||||
parsingConfig={parsingConfig}
|
||||
xAxis={xAxis}
|
||||
@ -83,10 +79,8 @@ export const PlotlyLineChart: React.FC<PlotlyLineChartProps> = ({
|
||||
};
|
||||
|
||||
const LineChartInner: React.FC<PlotlyLineChartProps> = ({
|
||||
url,
|
||||
data,
|
||||
rawCsv,
|
||||
randomId,
|
||||
uniqueId,
|
||||
bytes,
|
||||
parsingConfig,
|
||||
xAxis,
|
||||
@ -94,18 +88,22 @@ const LineChartInner: React.FC<PlotlyLineChartProps> = ({
|
||||
lineLabel,
|
||||
title,
|
||||
}) => {
|
||||
if (data) {
|
||||
const values = data.values;
|
||||
const url = data.url;
|
||||
const csv = data.csv;
|
||||
|
||||
if (values) {
|
||||
return (
|
||||
<div className="w-full" style={{ height: "500px" }}>
|
||||
<div className="w-full" style={{ height: '500px' }}>
|
||||
<Plotly
|
||||
layout={{
|
||||
title,
|
||||
}}
|
||||
data={[
|
||||
{
|
||||
x: data.map((d) => d[xAxis]),
|
||||
y: data.map((d) => d[yAxis]),
|
||||
mode: "lines",
|
||||
x: values.map((d) => d[xAxis]),
|
||||
y: values.map((d) => d[yAxis]),
|
||||
mode: 'lines',
|
||||
name: lineLabel,
|
||||
},
|
||||
]}
|
||||
@ -114,18 +112,18 @@ const LineChartInner: React.FC<PlotlyLineChartProps> = ({
|
||||
);
|
||||
}
|
||||
const { data: csvString, isLoading: isDownloadingCSV } = useQuery(
|
||||
["dataCsv", url, randomId],
|
||||
['dataCsv', url, uniqueId],
|
||||
() => getCsv(url as string, bytes ?? 5132288),
|
||||
{ enabled: !!url },
|
||||
{ enabled: !!url }
|
||||
);
|
||||
const { data: parsedData, isLoading: isParsing } = useQuery(
|
||||
["dataPreview", csvString, randomId],
|
||||
['dataPreview', csvString, uniqueId],
|
||||
() =>
|
||||
parseCsv(
|
||||
rawCsv ? (rawCsv as string) : (csvString as string),
|
||||
parsingConfig ?? {},
|
||||
csv ? (csv as string) : (csvString as string),
|
||||
parsingConfig ?? {}
|
||||
),
|
||||
{ enabled: rawCsv ? true : !!csvString },
|
||||
{ enabled: csv ? true : !!csvString }
|
||||
);
|
||||
if (isParsing || isDownloadingCSV)
|
||||
<div className="w-full flex justify-center items-center h-[500px]">
|
||||
@ -133,7 +131,7 @@ const LineChartInner: React.FC<PlotlyLineChartProps> = ({
|
||||
</div>;
|
||||
if (parsedData)
|
||||
return (
|
||||
<div className="w-full" style={{ height: "500px" }}>
|
||||
<div className="w-full" style={{ height: '500px' }}>
|
||||
<Plotly
|
||||
layout={{
|
||||
title,
|
||||
@ -142,7 +140,7 @@ const LineChartInner: React.FC<PlotlyLineChartProps> = ({
|
||||
{
|
||||
x: parsedData.data.map((d: any) => d[xAxis]),
|
||||
y: parsedData.data.map((d: any) => d[yAxis]),
|
||||
mode: "lines",
|
||||
mode: 'lines',
|
||||
name: lineLabel,
|
||||
},
|
||||
]}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// Wrapper for the Vega component
|
||||
import { Vega as VegaOg } from "react-vega";
|
||||
import { VegaProps } from "react-vega/lib/Vega";
|
||||
|
||||
export function Vega(props) {
|
||||
export function Vega(props: VegaProps) {
|
||||
return <VegaOg {...props} />;
|
||||
}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
// Wrapper for the Vega Lite component
|
||||
import { VegaLite as VegaLiteOg } from "react-vega";
|
||||
import applyFullWidthDirective from "../lib/applyFullWidthDirective";
|
||||
import { VegaLite as VegaLiteOg } from 'react-vega';
|
||||
import { VegaLiteProps } from 'react-vega/lib/VegaLite';
|
||||
import applyFullWidthDirective from '../lib/applyFullWidthDirective';
|
||||
|
||||
export function VegaLite(props) {
|
||||
export function VegaLite(props: VegaLiteProps) {
|
||||
const Component = applyFullWidthDirective({ Component: VegaLiteOg });
|
||||
|
||||
return <Component {...props} />;
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
export * from './components/Table';
|
||||
export * from './components/Catalog';
|
||||
export * from './components/LineChart';
|
||||
export * from './components/Vega';
|
||||
export * from './components/VegaLite';
|
||||
export * from './components/FlatUiTable';
|
||||
export * from './components/OpenLayers/OpenLayers';
|
||||
export * from './components/Map';
|
||||
export * from './components/PdfViewer';
|
||||
export * from "./components/Excel";
|
||||
export * from "./components/BucketViewer";
|
||||
export * from "./components/Iframe";
|
||||
export * from "./components/Plotly";
|
||||
export * from "./components/PlotlyLineChart";
|
||||
export * from "./components/PlotlyBarChart";
|
||||
// NOTE: components that are hidden for now
|
||||
// TODO: deprecate those components?
|
||||
// export * from './components/Table';
|
||||
// export * from "./components/BucketViewer";
|
||||
// export * from './components/OpenLayers/OpenLayers';
|
||||
|
||||
18
packages/components/src/types/properties.ts
Normal file
18
packages/components/src/types/properties.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* All components should use this interface for
|
||||
* its data property.
|
||||
* Based on vega.
|
||||
*
|
||||
*/
|
||||
|
||||
type URL = string; // Just in case we want to transform it into an object with configurations
|
||||
export interface Data {
|
||||
url?: URL;
|
||||
values?: { [key: string]: number | string }[];
|
||||
csv?: string;
|
||||
}
|
||||
|
||||
export interface GeospatialData {
|
||||
url?: URL;
|
||||
geojson?: GeoJSON.GeoJSON;
|
||||
}
|
||||
@ -1,74 +0,0 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { PlotlyBarChart, PlotlyBarChartProps } from '../src/components/PlotlyBarChart';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
title: 'Components/PlotlyBarChart',
|
||||
component: PlotlyBarChart,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
url: {
|
||||
description:
|
||||
'CSV Url to be parsed and used as data source',
|
||||
},
|
||||
data: {
|
||||
description:
|
||||
'Data to be displayed. as an array of key value pairs \n\n E.g.: [{ year: 1850, temperature: -0.41765878 }, { year: 1851, temperature: -0.2333498 }, ...]',
|
||||
},
|
||||
rawCsv: {
|
||||
description:
|
||||
'Raw csv data to be parsed and used as data source',
|
||||
},
|
||||
bytes: {
|
||||
description:
|
||||
'How many bytes to read from the url',
|
||||
},
|
||||
parsingConfig: {
|
||||
description: 'If using url or rawCsv, this parsing config will be used to parse the data. Optional, check https://www.papaparse.com/ for more info',
|
||||
},
|
||||
title: {
|
||||
description: 'Title to display on the chart. Optional.',
|
||||
},
|
||||
lineLabel: {
|
||||
description: 'Label to display on the line, Optional, will use yAxis if not provided',
|
||||
},
|
||||
xAxis: {
|
||||
description:
|
||||
'Name of the X axis on the data. Required when the "data" parameter is an URL.',
|
||||
},
|
||||
yAxis: {
|
||||
description:
|
||||
'Name of the Y axis on the data. Required when the "data" parameter is an URL.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<PlotlyBarChartProps>;
|
||||
|
||||
export const FromDataPoints: Story = {
|
||||
name: 'Line chart from array of data points',
|
||||
args: {
|
||||
data: [
|
||||
{year: '1850', temperature: -0.41765878},
|
||||
{year: '1851', temperature: -0.2333498},
|
||||
{year: '1852', temperature: -0.22939907},
|
||||
{year: '1853', temperature: -0.27035445},
|
||||
{year: '1854', temperature: -0.29163003},
|
||||
],
|
||||
xAxis: 'year',
|
||||
yAxis: 'temperature',
|
||||
},
|
||||
};
|
||||
|
||||
export const FromURL: Story = {
|
||||
name: 'Line chart from URL',
|
||||
args: {
|
||||
title: 'Apple Stock Prices',
|
||||
url: 'https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv',
|
||||
xAxis: 'Date',
|
||||
yAxis: 'AAPL.Open',
|
||||
},
|
||||
};
|
||||
@ -1,3 +1,6 @@
|
||||
// NOTE: this component was renamed with .bkp so that it's hidden
|
||||
// from the Storybook app
|
||||
|
||||
import { type Meta, type StoryObj } from '@storybook/react';
|
||||
|
||||
import {
|
||||
@ -10,11 +10,14 @@ const meta: Meta = {
|
||||
argTypes: {
|
||||
datasets: {
|
||||
description:
|
||||
'Lists of datasets to be displayed in the list, will usually be automatically available',
|
||||
"Array of items to be displayed on the searchable list. Must have the following properties: \n\n \
|
||||
`_id`: item's unique id \n\n \
|
||||
`url_path`: href of the item \n\n \
|
||||
`metadata`: object with a `title` property, that will be displayed as the title of the item, together with any other custom fields that might or not be faceted.",
|
||||
},
|
||||
facets: {
|
||||
description:
|
||||
'List of frontmatter fields that should be used as filters, needs to match exactly with the field name',
|
||||
"Array of strings, which are name of properties in the datasets' `metadata`, which are going to be faceted.",
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -31,99 +34,35 @@ export const WithoutFacets: Story = {
|
||||
{
|
||||
_id: '07026b22d49916754df1dc8ffb9ccd1c31878aae',
|
||||
url_path: 'dataset-4',
|
||||
file_path: 'content/dataset-4/index.md',
|
||||
metadata: {
|
||||
title: 'Detecting Abusive Albanian',
|
||||
'link-to-publication': 'https://arxiv.org/abs/2107.13592',
|
||||
'link-to-data': 'https://doi.org/10.6084/m9.figshare.19333298.v1',
|
||||
'task-description':
|
||||
'Hierarchical (offensive/not; untargeted/targeted; person/group/other)',
|
||||
'details-of-task':
|
||||
'Detect and categorise abusive language in social media data',
|
||||
'size-of-dataset': 11874,
|
||||
'percentage-abusive': 13.2,
|
||||
language: 'Albanian',
|
||||
'level-of-annotation': ['Posts'],
|
||||
platform: ['Instagram', 'Youtube'],
|
||||
medium: ['Text'],
|
||||
reference:
|
||||
'Nurce, E., Keci, J., Derczynski, L., 2021. Detecting Abusive Albanian. arXiv:2107.13592',
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: '42c86cf3c4fbbab11d91c2a7d6dcb8f750bc4e19',
|
||||
url_path: 'dataset-1',
|
||||
file_path: 'content/dataset-1/index.md',
|
||||
metadata: {
|
||||
title: 'AbuseEval v1.0',
|
||||
'link-to-publication':
|
||||
'http://www.lrec-conf.org/proceedings/lrec2020/pdf/2020.lrec-1.760.pdf',
|
||||
'link-to-data': 'https://github.com/tommasoc80/AbuseEval',
|
||||
'task-description':
|
||||
'Explicitness annotation of offensive and abusive content',
|
||||
'details-of-task':
|
||||
'Enriched versions of the OffensEval/OLID dataset with the distinction of explicit/implicit offensive messages and the new dimension for abusive messages. Labels for offensive language: EXPLICIT, IMPLICT, NOT; Labels for abusive language: EXPLICIT, IMPLICT, NOTABU',
|
||||
'size-of-dataset': 14100,
|
||||
'percentage-abusive': 20.75,
|
||||
language: 'English',
|
||||
'level-of-annotation': ['Tweets'],
|
||||
platform: ['Twitter'],
|
||||
medium: ['Text'],
|
||||
reference:
|
||||
'Caselli, T., Basile, V., Jelena, M., Inga, K., and Michael, G. 2020. "I feel offended, don’t be abusive! implicit/explicit messages in offensive and abusive language". The 12th Language Resources and Evaluation Conference (pp. 6193-6202). European Language Resources Association.',
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: '80001dd32a752421fdcc64e91fbd237dc31d6bb3',
|
||||
url_path: 'dataset-2',
|
||||
file_path: 'content/dataset-2/index.md',
|
||||
metadata: {
|
||||
title:
|
||||
'Abusive Language Detection on Arabic Social Media (Al Jazeera)',
|
||||
'link-to-publication': 'https://www.aclweb.org/anthology/W17-3008',
|
||||
'link-to-data':
|
||||
'http://alt.qcri.org/~hmubarak/offensive/AJCommentsClassification-CF.xlsx',
|
||||
'task-description':
|
||||
'Ternary (Obscene, Offensive but not obscene, Clean)',
|
||||
'details-of-task': 'Incivility',
|
||||
'size-of-dataset': 32000,
|
||||
'percentage-abusive': 0.81,
|
||||
language: 'Arabic',
|
||||
'level-of-annotation': ['Posts'],
|
||||
platform: ['AlJazeera'],
|
||||
medium: ['Text'],
|
||||
reference:
|
||||
'Mubarak, H., Darwish, K. and Magdy, W., 2017. Abusive Language Detection on Arabic Social Media. In: Proceedings of the First Workshop on Abusive Language Online. Vancouver, Canada: Association for Computational Linguistics, pp.52-56.',
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: '96649d05d8193f4333b10015af76c6562971bd8c',
|
||||
url_path: 'dataset-3',
|
||||
file_path: 'content/dataset-3/index.md',
|
||||
metadata: {
|
||||
title: 'CoRAL: a Context-aware Croatian Abusive Language Dataset',
|
||||
'link-to-publication':
|
||||
'https://aclanthology.org/2022.findings-aacl.21/',
|
||||
'link-to-data':
|
||||
'https://github.com/shekharRavi/CoRAL-dataset-Findings-of-the-ACL-AACL-IJCNLP-2022',
|
||||
'task-description':
|
||||
'Multi-class based on context dependency categories (CDC)',
|
||||
'details-of-task': 'Detectioning CDC from abusive comments',
|
||||
'size-of-dataset': 2240,
|
||||
'percentage-abusive': 100,
|
||||
language: 'Croatian',
|
||||
'level-of-annotation': ['Posts'],
|
||||
platform: ['Posts'],
|
||||
medium: ['Newspaper Comments'],
|
||||
reference:
|
||||
'Ravi Shekhar, Mladen Karan and Matthew Purver (2022). CoRAL: a Context-aware Croatian Abusive Language Dataset. Findings of the ACL: AACL-IJCNLP.',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
;
|
||||
|
||||
export const WithFacets: Story = {
|
||||
name: 'Catalog with facets',
|
||||
args: {
|
||||
@ -131,7 +70,6 @@ export const WithFacets: Story = {
|
||||
{
|
||||
_id: '07026b22d49916754df1dc8ffb9ccd1c31878aae',
|
||||
url_path: 'dataset-4',
|
||||
file_path: 'content/dataset-4/index.md',
|
||||
metadata: {
|
||||
title: 'Detecting Abusive Albanian',
|
||||
'link-to-publication': 'https://arxiv.org/abs/2107.13592',
|
||||
@ -220,7 +158,6 @@ export const WithFacets: Story = {
|
||||
},
|
||||
},
|
||||
],
|
||||
facets: ['language', 'platform']
|
||||
facets: ['language', 'platform'],
|
||||
},
|
||||
};
|
||||
;
|
||||
|
||||
@ -4,13 +4,13 @@ import { Excel, ExcelProps } from '../src/components/Excel';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
title: 'Components/Excel',
|
||||
title: 'Components/Tabular/Excel',
|
||||
component: Excel,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
url: {
|
||||
data: {
|
||||
description:
|
||||
'Url of the file to be displayed e.g.: "https://url.to/data.csv"',
|
||||
'Object with a `url` property pointing to the Excel file to be displayed, e.g.: `{ url: "https://url.to/data.csv" }`',
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -22,13 +22,17 @@ type Story = StoryObj<ExcelProps>;
|
||||
export const SingleSheet: Story = {
|
||||
name: 'Excel file with just one sheet',
|
||||
args: {
|
||||
url: 'https://sheetjs.com/pres.xlsx',
|
||||
data: {
|
||||
url: 'https://sheetjs.com/pres.xlsx',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const MultipleSheet: Story = {
|
||||
name: 'Excel file with multiple sheets',
|
||||
args: {
|
||||
url: 'https://storage.portaljs.org/IC-Gantt-Chart-Project-Template-8857.xlsx',
|
||||
data: {
|
||||
url: 'https://storage.portaljs.org/IC-Gantt-Chart-Project-Template-8857.xlsx',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -4,29 +4,31 @@ import { FlatUiTable, FlatUiTableProps } from '../src/components/FlatUiTable';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
title: 'Components/FlatUiTable',
|
||||
title: 'Components/Tabular/FlatUiTable',
|
||||
component: FlatUiTable,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
data: {
|
||||
description:
|
||||
'Data to be displayed in the table, must be setup as an array of key value pairs',
|
||||
},
|
||||
csv: {
|
||||
description: 'CSV data as string.',
|
||||
},
|
||||
url: {
|
||||
description:
|
||||
'Fetch the data from a CSV file remotely. only the first 5MB of data will be displayed',
|
||||
'Data to be displayed. \n\n \
|
||||
Must be an object with one of the following properties: `url`, `values` or `csv` \n\n \
|
||||
`url`: URL pointing to a CSV file. \n\n \
|
||||
`values`: array of objects. \n\n \
|
||||
`csv`: string with valid CSV. \n\n \
|
||||
',
|
||||
},
|
||||
bytes: {
|
||||
description:
|
||||
'Fetch the data from a CSV file remotely. only the first <bytes> of data will be displayed',
|
||||
'Fetch the data from a CSV file remotely. Only the first <bytes> of data will be displayed. Defaults to 5MB.',
|
||||
},
|
||||
parsingConfig: {
|
||||
description:
|
||||
'Configuration for parsing the CSV data. See https://www.papaparse.com/docs#config for more details',
|
||||
},
|
||||
uniqueId: {
|
||||
description:
|
||||
'Provide a unique ID to help with cache revalidation of the fetched data.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -36,34 +38,40 @@ type Story = StoryObj<FlatUiTableProps>;
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
export const FromColumnsAndData: Story = {
|
||||
name: 'Table data',
|
||||
name: 'Table from array or objects',
|
||||
args: {
|
||||
data: [
|
||||
{ id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 },
|
||||
{ id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 },
|
||||
{ id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 },
|
||||
{ id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 },
|
||||
{ id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 },
|
||||
{ id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 },
|
||||
{ id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 },
|
||||
],
|
||||
data: {
|
||||
values: [
|
||||
{ id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 },
|
||||
{ id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 },
|
||||
{ id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 },
|
||||
{ id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 },
|
||||
{ id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 },
|
||||
{ id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 },
|
||||
{ id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const FromRawCSV: Story = {
|
||||
name: 'Table from raw CSV',
|
||||
name: 'Table from inline CSV',
|
||||
args: {
|
||||
rawCsv: `
|
||||
data: {
|
||||
csv: `
|
||||
Year,Temp Anomaly
|
||||
1850,-0.418
|
||||
2020,0.923
|
||||
`,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const FromURL: Story = {
|
||||
name: 'Table from URL',
|
||||
args: {
|
||||
url: 'https://storage.openspending.org/alberta-budget/__os_imported__alberta_total.csv',
|
||||
data: {
|
||||
url: 'https://storage.openspending.org/alberta-budget/__os_imported__alberta_total.csv',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -3,17 +3,17 @@ import { type Meta, type StoryObj } from '@storybook/react';
|
||||
import { Iframe, IframeProps } from '../src/components/Iframe';
|
||||
|
||||
const meta: Meta = {
|
||||
title: 'Components/Iframe',
|
||||
title: 'Components/Embedding/Iframe',
|
||||
component: Iframe,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
url: {
|
||||
data: {
|
||||
description:
|
||||
'Page to display inside of the component',
|
||||
'Object with a `url` property pointing to the page to be embeded.',
|
||||
},
|
||||
style: {
|
||||
description:
|
||||
'Style of the component',
|
||||
'Style object of the component. See example at https://react.dev/learn#displaying-data. Defaults to `{ width: "100%", height: "100%" }`',
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -25,7 +25,9 @@ type Story = StoryObj<IframeProps>;
|
||||
export const Normal: Story = {
|
||||
name: 'Iframe',
|
||||
args: {
|
||||
url: 'https://app.powerbi.com/view?r=eyJrIjoiYzBmN2Q2MzYtYzE3MS00ODkxLWE5OWMtZTQ2MjBlMDljMDk4IiwidCI6Ijk1M2IwZjgzLTFjZTYtNDVjMy04MmM5LTFkODQ3ZTM3MjMzOSIsImMiOjh9',
|
||||
style: {width: `100%`, height: `100%`}
|
||||
data: {
|
||||
url: 'https://app.powerbi.com/view?r=eyJrIjoiYzBmN2Q2MzYtYzE3MS00ODkxLWE5OWMtZTQ2MjBlMDljMDk4IiwidCI6Ijk1M2IwZjgzLTFjZTYtNDVjMy04MmM5LTFkODQ3ZTM3MjMzOSIsImMiOjh9',
|
||||
},
|
||||
style: { width: `100%`, height: `100%` },
|
||||
},
|
||||
};
|
||||
|
||||
@ -4,37 +4,36 @@ import { LineChart, LineChartProps } from '../src/components/LineChart';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
title: 'Components/LineChart',
|
||||
title: 'Components/Charts/LineChart',
|
||||
component: LineChart,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
data: {
|
||||
description:
|
||||
'Data to be displayed.\n\n E.g.: [["1990", 1], ["1991", 2]] \n\nOR\n\n "https://url.to/data.csv"',
|
||||
'Data to be displayed. \n\n \
|
||||
Must be an object with one of the following properties: `url` or `values` \n\n \
|
||||
`url`: URL pointing to a CSV file. \n\n \
|
||||
`values`: array of objects \n\n',
|
||||
},
|
||||
title: {
|
||||
description: 'Title to display on the chart. Optional.',
|
||||
description: 'Title to display on the chart.',
|
||||
},
|
||||
xAxis: {
|
||||
description:
|
||||
'Name of the X axis on the data. Required when the "data" parameter is an URL.',
|
||||
'Name of the column header or object property that represents the X-axis on the data.',
|
||||
},
|
||||
xAxisType: {
|
||||
description: 'Type of the X axis',
|
||||
description: 'Type of the X-axis.',
|
||||
},
|
||||
xAxisTimeUnit: {
|
||||
description: 'Time unit of the X axis (optional)',
|
||||
description: 'Time unit of the X-axis, in case its type is `temporal.`',
|
||||
},
|
||||
yAxis: {
|
||||
description:
|
||||
'Name of the Y axis on the data. Required when the "data" parameter is an URL.',
|
||||
'Name of the column header or object property that represents the Y-axis on the data.',
|
||||
},
|
||||
yAxisType: {
|
||||
description: 'Type of the Y axis',
|
||||
},
|
||||
fullWidth: {
|
||||
description:
|
||||
'Whether the component should be rendered as full bleed or not',
|
||||
description: 'Type of the Y-axis',
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -47,21 +46,27 @@ type Story = StoryObj<LineChartProps>;
|
||||
export const FromDataPoints: Story = {
|
||||
name: 'Line chart from array of data points',
|
||||
args: {
|
||||
data: [
|
||||
['1850', -0.41765878],
|
||||
['1851', -0.2333498],
|
||||
['1852', -0.22939907],
|
||||
['1853', -0.27035445],
|
||||
['1854', -0.29163003],
|
||||
],
|
||||
data: {
|
||||
values: [
|
||||
{ year: '1850', value: -0.41765878 },
|
||||
{ year: '1851', value: -0.2333498 },
|
||||
{ year: '1852', value: -0.22939907 },
|
||||
{ year: '1853', value: -0.27035445 },
|
||||
{ year: '1854', value: -0.29163003 },
|
||||
],
|
||||
},
|
||||
xAxis: 'year',
|
||||
yAxis: 'value',
|
||||
},
|
||||
};
|
||||
|
||||
export const FromURL: Story = {
|
||||
name: 'Line chart from URL',
|
||||
args: {
|
||||
data: {
|
||||
url: 'https://raw.githubusercontent.com/datasets/oil-prices/main/data/wti-year.csv',
|
||||
},
|
||||
title: 'Oil Price x Year',
|
||||
data: 'https://raw.githubusercontent.com/datasets/oil-prices/main/data/wti-year.csv',
|
||||
xAxis: 'Date',
|
||||
yAxis: 'Price',
|
||||
},
|
||||
|
||||
@ -1,74 +0,0 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { PlotlyLineChart, PlotlyLineChartProps } from '../src/components/PlotlyLineChart';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
title: 'Components/PlotlyLineChart',
|
||||
component: PlotlyLineChart,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
url: {
|
||||
description:
|
||||
'CSV Url to be parsed and used as data source',
|
||||
},
|
||||
data: {
|
||||
description:
|
||||
'Data to be displayed. as an array of key value pairs \n\n E.g.: [{ year: 1850, temperature: -0.41765878 }, { year: 1851, temperature: -0.2333498 }, ...]',
|
||||
},
|
||||
rawCsv: {
|
||||
description:
|
||||
'Raw csv data to be parsed and used as data source',
|
||||
},
|
||||
bytes: {
|
||||
description:
|
||||
'How many bytes to read from the url',
|
||||
},
|
||||
parsingConfig: {
|
||||
description: 'If using url or rawCsv, this parsing config will be used to parse the data. Optional, check https://www.papaparse.com/ for more info',
|
||||
},
|
||||
title: {
|
||||
description: 'Title to display on the chart. Optional.',
|
||||
},
|
||||
lineLabel: {
|
||||
description: 'Label to display on the line, Optional, will use yAxis if not provided',
|
||||
},
|
||||
xAxis: {
|
||||
description:
|
||||
'Name of the X axis on the data. Required when the "data" parameter is an URL.',
|
||||
},
|
||||
yAxis: {
|
||||
description:
|
||||
'Name of the Y axis on the data. Required when the "data" parameter is an URL.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<PlotlyLineChartProps>;
|
||||
|
||||
export const FromDataPoints: Story = {
|
||||
name: 'Line chart from array of data points',
|
||||
args: {
|
||||
data: [
|
||||
{year: '1850', temperature: -0.41765878},
|
||||
{year: '1851', temperature: -0.2333498},
|
||||
{year: '1852', temperature: -0.22939907},
|
||||
{year: '1853', temperature: -0.27035445},
|
||||
{year: '1854', temperature: -0.29163003},
|
||||
],
|
||||
xAxis: 'year',
|
||||
yAxis: 'temperature',
|
||||
},
|
||||
};
|
||||
|
||||
export const FromURL: Story = {
|
||||
name: 'Line chart from URL',
|
||||
args: {
|
||||
title: 'Oil Price x Year',
|
||||
url: 'https://raw.githubusercontent.com/datasets/oil-prices/main/data/wti-year.csv',
|
||||
xAxis: 'Date',
|
||||
yAxis: 'Price',
|
||||
},
|
||||
};
|
||||
@ -4,29 +4,34 @@ import { Map, MapProps } from '../src/components/Map';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
title: 'Components/Map',
|
||||
title: 'Components/Geospatial/Map',
|
||||
component: Map,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
layers: {
|
||||
description:
|
||||
'Data to be displayed.\n\n GeoJSON Object \n\nOR\n\n URL to GeoJSON Object',
|
||||
'Array of layers to be displayed on the map. Should be an object with: \n\n \
|
||||
`data`: object with either a `url` property pointing to a GeoJSON file or a `geojson` property with a GeoJSON object. \n\n \
|
||||
`name`: name of the layer. \n\n \
|
||||
`colorscale`: object with a `starting` and `ending` colors that will be used to create a gradient and color the map. \n\n \
|
||||
`tooltip`: `true` to show all available features on the tooltip, object with a `propNames` property as an array of strings to choose which features to display. \n\n',
|
||||
},
|
||||
title: {
|
||||
description: 'Title to display on the map. Optional.',
|
||||
description: 'Title to display on the map.',
|
||||
},
|
||||
center: {
|
||||
description: 'Initial coordinates of the center of the map',
|
||||
},
|
||||
zoom: {
|
||||
description: 'Zoom level',
|
||||
description: 'Initial zoom level',
|
||||
},
|
||||
style: {
|
||||
description: "Styles for the container"
|
||||
description: "CSS styles to be applied to the map's container.",
|
||||
},
|
||||
autoZoomConfiguration: {
|
||||
description: "Configuration to auto zoom in the specified layer data"
|
||||
}
|
||||
description:
|
||||
"Pass a layer's name to automatically zoom to the bounding area of a layer.",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -40,7 +45,9 @@ export const GeoJSONPolygons: Story = {
|
||||
args: {
|
||||
layers: [
|
||||
{
|
||||
data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson',
|
||||
data: {
|
||||
url: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson',
|
||||
},
|
||||
name: 'Polygons',
|
||||
tooltip: { propNames: ['name'] },
|
||||
colorScale: {
|
||||
@ -60,7 +67,9 @@ export const GeoJSONPoints: Story = {
|
||||
args: {
|
||||
layers: [
|
||||
{
|
||||
data: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson',
|
||||
data: {
|
||||
url: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson',
|
||||
},
|
||||
name: 'Points',
|
||||
tooltip: { propNames: ['Location'] },
|
||||
},
|
||||
@ -76,12 +85,16 @@ export const GeoJSONMultipleLayers: Story = {
|
||||
args: {
|
||||
layers: [
|
||||
{
|
||||
data: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson',
|
||||
data: {
|
||||
url: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson',
|
||||
},
|
||||
name: 'Points',
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson',
|
||||
data: {
|
||||
url: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson',
|
||||
},
|
||||
name: 'Polygons',
|
||||
tooltip: true,
|
||||
colorScale: {
|
||||
@ -94,19 +107,23 @@ export const GeoJSONMultipleLayers: Story = {
|
||||
center: { latitude: 45, longitude: 0 },
|
||||
zoom: 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export const GeoJSONMultipleLayersWithAutoZoomInSpecifiedLayer: Story = {
|
||||
name: 'GeoJSON polygons and points map with auto zoom in the points layer',
|
||||
args: {
|
||||
layers: [
|
||||
{
|
||||
data: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson',
|
||||
data: {
|
||||
url: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson',
|
||||
},
|
||||
name: 'Points',
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson',
|
||||
data: {
|
||||
url: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson',
|
||||
},
|
||||
name: 'Polygons',
|
||||
tooltip: true,
|
||||
colorScale: {
|
||||
@ -119,7 +136,7 @@ export const GeoJSONMultipleLayersWithAutoZoomInSpecifiedLayer: Story = {
|
||||
center: { latitude: 45, longitude: 0 },
|
||||
zoom: 2,
|
||||
autoZoomConfiguration: {
|
||||
layerName: 'Points'
|
||||
}
|
||||
layerName: 'Points',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
// NOTE: this component was renamed with .bkp so that it's hidden
|
||||
// from the Storybook app
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import OpenLayers from '../src/components/OpenLayers/OpenLayers';
|
||||
@ -3,19 +3,21 @@ import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { PdfViewer, PdfViewerProps } from '../src/components/PdfViewer';
|
||||
|
||||
const meta: Meta = {
|
||||
title: 'Components/PdfViewer',
|
||||
title: 'Components/Embedding/PdfViewer',
|
||||
component: PdfViewer,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
url: {
|
||||
description: 'URL to PDF file',
|
||||
data: {
|
||||
description:
|
||||
'Object with a `url` property pointing to the PDF file to be displayed, e.g.: `{ url: "https://cdn.filestackcontent.com/wcrjf9qPTCKXV3hMXDwK" }`.',
|
||||
},
|
||||
parentClassName: {
|
||||
description: 'Classname for the parent div of the pdf viewer',
|
||||
},
|
||||
layour: {
|
||||
description:
|
||||
'Set to true if you want to have a layout with zoom level, page count, printing button etc',
|
||||
'HTML classes to be applied to the container of the PDF viewer. [Tailwind](https://tailwindcss.com/) classes, such as `h-96` to define the height of the component, can be used on this field.',
|
||||
},
|
||||
layout: {
|
||||
description:
|
||||
'Set to `true` if you want to display a layout with zoom level, page count, printing button and other controls.',
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
@ -25,26 +27,23 @@ export default meta;
|
||||
|
||||
type Story = StoryObj<PdfViewerProps>;
|
||||
|
||||
export const PdfViewerStory: Story = {
|
||||
name: 'PdfViewer',
|
||||
export const PdfViewerStoryWithoutControlsLayout: Story = {
|
||||
name: 'PDF Viewer without controls layout',
|
||||
args: {
|
||||
url: 'https://cdn.filestackcontent.com/wcrjf9qPTCKXV3hMXDwK',
|
||||
},
|
||||
};
|
||||
|
||||
export const PdfViewerStoryWithLayout: Story = {
|
||||
name: 'PdfViewer with the default layout',
|
||||
args: {
|
||||
url: 'https://cdn.filestackcontent.com/wcrjf9qPTCKXV3hMXDwK',
|
||||
layout: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const PdfViewerStoryWithHeight: Story = {
|
||||
name: 'PdfViewer with a custom height',
|
||||
args: {
|
||||
url: 'https://cdn.filestackcontent.com/wcrjf9qPTCKXV3hMXDwK',
|
||||
data: {
|
||||
url: 'https://cdn.filestackcontent.com/wcrjf9qPTCKXV3hMXDwK',
|
||||
},
|
||||
parentClassName: 'h-96',
|
||||
},
|
||||
};
|
||||
|
||||
export const PdfViewerStoryWithControlsLayout: Story = {
|
||||
name: 'PdfViewer with controls layout',
|
||||
args: {
|
||||
data: {
|
||||
url: 'https://cdn.filestackcontent.com/wcrjf9qPTCKXV3hMXDwK',
|
||||
},
|
||||
layout: true,
|
||||
parentClassName: 'h-96',
|
||||
layout: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -4,9 +4,19 @@ import { Plotly } from '../src/components/Plotly';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
title: 'Components/Plotly',
|
||||
title: 'Components/Charts/Plotly',
|
||||
component: Plotly,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
data: {
|
||||
description:
|
||||
"Plotly's `data` prop. You can find references on how to use these props at https://github.com/plotly/react-plotly.js/#basic-props.",
|
||||
},
|
||||
layout: {
|
||||
description:
|
||||
"Plotly's `layout` prop. You can find references on how to use these props at https://github.com/plotly/react-plotly.js/#basic-props.",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
@ -15,7 +25,7 @@ type Story = StoryObj<any>;
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
export const Primary: Story = {
|
||||
name: 'Chart built with Plotly',
|
||||
name: 'Line chart',
|
||||
args: {
|
||||
data: [
|
||||
{
|
||||
|
||||
102
packages/components/stories/PlotlyBarChart.stories.ts
Normal file
102
packages/components/stories/PlotlyBarChart.stories.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import {
|
||||
PlotlyBarChart,
|
||||
PlotlyBarChartProps,
|
||||
} from '../src/components/PlotlyBarChart';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
title: 'Components/Charts/PlotlyBarChart',
|
||||
component: PlotlyBarChart,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
data: {
|
||||
description:
|
||||
'Data to be displayed. \n\n \
|
||||
Must be an object with one of the following properties: `url`, `values` or `csv` \n\n \
|
||||
`url`: URL pointing to a CSV file. \n\n \
|
||||
`values`: array of objects (check out [this example](/?path=/story/components-plotlybarchart--from-data-points)) \n\n \
|
||||
`csv`: string with valid CSV (check out [this example](/?path=/story/components-plotlybarchart--from-inline-csv)) \n\n \
|
||||
',
|
||||
},
|
||||
bytes: {
|
||||
// TODO: likely this should be an extra option on the data parameter,
|
||||
// specific to URLs
|
||||
description:
|
||||
"How many bytes to read from the url so that the entire file doesn's have to be fetched.",
|
||||
},
|
||||
parsingConfig: {
|
||||
description:
|
||||
'If using URL or CSV, this parsing config will be used to parse the data. Check https://www.papaparse.com/ for more info.',
|
||||
},
|
||||
title: {
|
||||
description: 'Title to display on the chart.',
|
||||
},
|
||||
// TODO: commented out because this doesn't work
|
||||
// lineLabel: {
|
||||
// description:
|
||||
// 'Label to display on the line, Optional, will use yAxis if not provided',
|
||||
// },
|
||||
xAxis: {
|
||||
description:
|
||||
'Name of the column header or object property that represents the X-axis on the data.',
|
||||
},
|
||||
yAxis: {
|
||||
description:
|
||||
'Name of the column header or object property that represents the Y-axis on the data.',
|
||||
},
|
||||
uniqueId: {
|
||||
description: 'Provide a unique ID to help with cache revalidation of the fetched data.'
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<PlotlyBarChartProps>;
|
||||
|
||||
export const FromDataPoints: Story = {
|
||||
name: 'Bar chart from array of data points',
|
||||
args: {
|
||||
data: {
|
||||
values: [
|
||||
{ year: '1850', temperature: -0.41765878 },
|
||||
{ year: '1851', temperature: -0.2333498 },
|
||||
{ year: '1852', temperature: -0.22939907 },
|
||||
{ year: '1853', temperature: -0.27035445 },
|
||||
{ year: '1854', temperature: -0.29163003 },
|
||||
],
|
||||
},
|
||||
xAxis: 'year',
|
||||
yAxis: 'temperature',
|
||||
},
|
||||
};
|
||||
|
||||
export const FromURL: Story = {
|
||||
name: 'Bar chart from URL',
|
||||
args: {
|
||||
title: 'Apple Stock Prices',
|
||||
data: {
|
||||
url: 'https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv',
|
||||
},
|
||||
xAxis: 'Date',
|
||||
yAxis: 'AAPL.Open',
|
||||
},
|
||||
};
|
||||
|
||||
export const FromInlineCSV: Story = {
|
||||
name: 'Bar chart from inline CSV',
|
||||
args: {
|
||||
title: 'Apple Stock Prices',
|
||||
data: {
|
||||
csv: `Date,AAPL.Open,AAPL.High,AAPL.Low,AAPL.Close,AAPL.Volume,AAPL.Adjusted,dn,mavg,up,direction
|
||||
2015-02-17,127.489998,128.880005,126.919998,127.830002,63152400,122.905254,106.7410523,117.9276669,129.1142814,Increasing
|
||||
2015-02-18,127.629997,128.779999,127.449997,128.720001,44891700,123.760965,107.842423,118.9403335,130.0382439,Increasing
|
||||
2015-02-19,128.479996,129.029999,128.330002,128.449997,37362400,123.501363,108.8942449,119.8891668,130.8840887,Decreasing
|
||||
2015-02-20,128.619995,129.5,128.050003,129.5,48948400,124.510914,109.7854494,120.7635001,131.7415509,Increasing`,
|
||||
},
|
||||
xAxis: 'Date',
|
||||
yAxis: 'AAPL.Open',
|
||||
},
|
||||
};
|
||||
101
packages/components/stories/PlotlyLineChart.stories.ts
Normal file
101
packages/components/stories/PlotlyLineChart.stories.ts
Normal file
@ -0,0 +1,101 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import {
|
||||
PlotlyLineChart,
|
||||
PlotlyLineChartProps,
|
||||
} from '../src/components/PlotlyLineChart';
|
||||
|
||||
const meta: Meta = {
|
||||
title: 'Components/Charts/PlotlyLineChart',
|
||||
component: PlotlyLineChart,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
data: {
|
||||
description:
|
||||
'Data to be displayed. \n\n \
|
||||
Must be an object with one of the following properties: `url`, `values` or `csv` \n\n \
|
||||
`url`: URL pointing to a CSV file. \n\n \
|
||||
`values`: array of objects. \n\n \
|
||||
`csv`: string with valid CSV. \n\n \
|
||||
',
|
||||
},
|
||||
bytes: {
|
||||
// TODO: likely this should be an extra option on the data parameter,
|
||||
// specific to URLs
|
||||
description:
|
||||
"How many bytes to read from the url so that the entire file doesn's have to be fetched.",
|
||||
},
|
||||
parsingConfig: {
|
||||
description:
|
||||
'If using URL or CSV, this parsing config will be used to parse the data. Check https://www.papaparse.com/ for more info',
|
||||
},
|
||||
title: {
|
||||
description: 'Title to display on the chart.',
|
||||
},
|
||||
lineLabel: {
|
||||
description:
|
||||
'Label to display on the line, will use yAxis if not provided',
|
||||
},
|
||||
xAxis: {
|
||||
description:
|
||||
'Name of the column header or object property that represents the X-axis on the data.',
|
||||
},
|
||||
yAxis: {
|
||||
description:
|
||||
'Name of the column header or object property that represents the Y-axis on the data.',
|
||||
},
|
||||
uniqueId: {
|
||||
description:
|
||||
'Provide a unique ID to help with cache revalidation of the fetched data.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<PlotlyLineChartProps>;
|
||||
|
||||
export const FromDataPoints: Story = {
|
||||
name: 'Line chart from array of data points',
|
||||
args: {
|
||||
data: {
|
||||
values: [
|
||||
{ year: '1850', temperature: -0.41765878 },
|
||||
{ year: '1851', temperature: -0.2333498 },
|
||||
{ year: '1852', temperature: -0.22939907 },
|
||||
{ year: '1853', temperature: -0.27035445 },
|
||||
{ year: '1854', temperature: -0.29163003 },
|
||||
],
|
||||
},
|
||||
xAxis: 'year',
|
||||
yAxis: 'temperature',
|
||||
},
|
||||
};
|
||||
|
||||
export const FromURL: Story = {
|
||||
name: 'Line chart from URL',
|
||||
args: {
|
||||
title: 'Oil Price x Year',
|
||||
data: {
|
||||
url: 'https://raw.githubusercontent.com/datasets/oil-prices/main/data/wti-year.csv',
|
||||
},
|
||||
xAxis: 'Date',
|
||||
yAxis: 'Price',
|
||||
},
|
||||
};
|
||||
|
||||
export const FromInlineCSV: Story = {
|
||||
name: 'Bar chart from inline CSV',
|
||||
args: {
|
||||
title: 'Apple Stock Prices',
|
||||
data: {
|
||||
csv: `Date,AAPL.Open,AAPL.High,AAPL.Low,AAPL.Close,AAPL.Volume,AAPL.Adjusted,dn,mavg,up,direction
|
||||
2015-02-17,127.489998,128.880005,126.919998,127.830002,63152400,122.905254,106.7410523,117.9276669,129.1142814,Increasing
|
||||
2015-02-18,127.629997,128.779999,127.449997,128.720001,44891700,123.760965,107.842423,118.9403335,130.0382439,Increasing
|
||||
2015-02-19,128.479996,129.029999,128.330002,128.449997,37362400,123.501363,108.8942449,119.8891668,130.8840887,Decreasing
|
||||
2015-02-20,128.619995,129.5,128.050003,129.5,48948400,124.510914,109.7854494,120.7635001,131.7415509,Increasing`,
|
||||
},
|
||||
xAxis: 'Date',
|
||||
yAxis: 'AAPL.Open',
|
||||
},
|
||||
};
|
||||
@ -1,10 +1,13 @@
|
||||
// NOTE: this component was renamed with .bkp so that it's hidden
|
||||
// from the Storybook app
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { Table, TableProps } from '../src/components/Table';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
title: 'Components/Table',
|
||||
title: 'Components/Tabular/Table',
|
||||
component: Table,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
@ -4,9 +4,19 @@ import { Vega } from '../src/components/Vega';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
title: 'Components/Vega',
|
||||
title: 'Components/Charts/Vega',
|
||||
component: Vega,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
data: {
|
||||
description:
|
||||
"Vega's `data` prop. You can find references on how to use this prop at https://vega.github.io/vega/docs/data/",
|
||||
},
|
||||
spec: {
|
||||
description:
|
||||
"Vega's `spec` prop. You can find references on how to use this prop at https://vega.github.io/vega/docs/specification/",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
@ -15,7 +25,7 @@ type Story = StoryObj<any>;
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
export const Primary: Story = {
|
||||
name: 'Chart built with Vega',
|
||||
name: 'Bar chart',
|
||||
args: {
|
||||
data: {
|
||||
table: [
|
||||
|
||||
@ -4,7 +4,7 @@ import { VegaLite } from '../src/components/VegaLite';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
title: 'Components/VegaLite',
|
||||
title: 'Components/Charts/VegaLite',
|
||||
component: VegaLite,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
@ -25,7 +25,7 @@ type Story = StoryObj<any>;
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
export const Primary: Story = {
|
||||
name: 'Chart built with Vega Lite',
|
||||
name: 'Bar chart',
|
||||
args: {
|
||||
data: {
|
||||
table: [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user