Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TimeRangePicker component #206

Merged
merged 23 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
629aa45
chore(ui-kit): temp
sashathor Feb 29, 2024
e9ba7e6
feat(ui-kit): improvements for TimePicker and releated components
sashathor Mar 28, 2024
cea296e
chore(ui-kit): updates
sashathor Mar 28, 2024
28c3b93
chore(deps): update lock files
sashathor Mar 28, 2024
373caba
chore(deps): update lock files
sashathor Apr 8, 2024
627254a
chore(time-picker): sync with new design tokens
sashathor Apr 17, 2024
34cc434
chore(ui-kit): add tests for TimeRangePicker
sashathor Apr 18, 2024
443ca53
chore(storybook): add docs for TimeRangePicker
sashathor Apr 18, 2024
d91d97f
chore(cicd): add changesets
sashathor Apr 18, 2024
def80cc
fix(ui-kit): TimeRangePicker minor fixes
sashathor Apr 18, 2024
c12a306
fix(ui-kit): fix TimeRangePicker tests
sashathor Apr 18, 2024
1541a12
chore(ui-kit,examples): TimeRangePicker fixes, add TimeRangePicker to…
sashathor Apr 22, 2024
7019680
chore(ui-kit, storybook): updates
sashathor May 2, 2024
a92a21f
chore(ui-kit): TimeRangePicker pr comment updates
sashathor May 6, 2024
48aa57c
chore(ui-kit): TimeRangePicker pr comment updates
sashathor May 7, 2024
91bae3a
chore(ui-kit): TimeRangePicker pr comment updates
sashathor May 13, 2024
25abea0
chore(ui-kit): TimeRangePicker pr comment updates
sashathor May 14, 2024
f8ca95c
fix(ui-kit): build fix
sashathor May 14, 2024
9825f93
fix(ui-kit): fix nested Selects
sashathor May 16, 2024
838e832
fix(ui-kit): fix TimeRangePicker
sashathor May 16, 2024
52cc607
chore(ui-kit): TimeRangePicker pr comment updates
sashathor May 17, 2024
fb786ee
fix(ui-kit): fix Select multiple clicks
sashathor May 20, 2024
ce41b55
fix(ui-kit): fix Select multiple clicks
sashathor May 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/loud-forks-repair.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@propeldata/ui-kit': minor
---

[Button, Divider, FormField, Input, Select, TimeRangePicker, Typography]: added new components
5 changes: 5 additions & 0 deletions .changeset/wicked-dragons-double.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@propeldata/ui-kit': patch
---

Sync all the UI components with new design tokens
12,932 changes: 6,571 additions & 6,361 deletions .pnp.cjs
100755 → 100644

Large diffs are not rendered by default.

24 changes: 11 additions & 13 deletions app/storybook/.storybook/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,22 @@ import { addons } from '@storybook/manager-api'
import { defaultTheme } from './defaultTheme'

const env = process.env.NODE_ENV
const devOnly = ['']
const hidden = ['Components/Autocomplete']

addons.setConfig({
theme: defaultTheme,
sidebar: {
filters: {
patterns: (item) => {
return !item.tags?.includes('pattern')
},
devOnly: (item) => {
return (
env !== 'production' ||
!devOnly
.concat(hidden)
.map((element) => element.toLowerCase())
.includes(item.title.toLowerCase())
)
/**
* Determines the visibility of Storybook stories based on their tags:
*
* - `hidden`: Excludes stories with this tag from all environments.
* - `devOnly`: Excludes stories with this tag from the production environment.
*
* Returns true if a story should be displayed, ensuring it does not have the 'hidden' tag,
* and, in production, does not have the 'devOnly' tag.
*/
patterns: (story) => {
return !story.tags?.includes('hidden') && !(env === 'production' && story.tags?.includes('devOnly'))
}
}
}
Expand Down
11 changes: 9 additions & 2 deletions app/storybook/.storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,25 @@ import './global.css'
const GlobalStyles = () => {
const theme = useTheme()
if (document && theme) {
document.body.style.setProperty('--bg-color', theme.bgSecondary as string)
document.body.style.setProperty('--bg-color', theme.backgroundSecondary as string)
}
return null
}

// const MyCustomButton = ({ children }: React.ComponentPropsWithoutRef<'button'>) => <button>{children}</button>
sashathor marked this conversation as resolved.
Show resolved Hide resolved

const withThemeProvider = (Story: React.FC, context: StoryContext) => {
if (context.parameters.skipThemeProvider) {
return <Story />
}

return (
<ThemeProvider baseTheme={context.globals.theme}>
<ThemeProvider
baseTheme={context.globals.theme}
// components={{
// Button: (props) => <MyCustomButton {...props} />
// }}
sashathor marked this conversation as resolved.
Show resolved Hide resolved
>
<GlobalStyles />
<Story />
</ThemeProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { Meta, Source, Canvas } from '@storybook/blocks'
import { SourceCode } from '../../.storybook/blocks/SourceCode'
import * as CounterStories from '../../../../packages/ui-kit/src/components/Counter/Counter.stories'

<Meta title="Customization/Fallbacks" />
<Meta title="Customization/Default components" />

# Fallbacks
# Default components

It's possible to customize the `Loading`, `Error`, and `Empty` states of the UI Kit components. This is useful when you
want to provide a consistent look and feel across your app. You can customize the fallbacks globally for all components
Expand All @@ -23,6 +23,10 @@ via `ThemeProvider`.
renderLoader={() => <div>Loading...</div>}
errorFallback={() => <h1>Error</h1>}
renderEmpty={() => <span>No Data</span>}
components={{
Input: ({ props }) => <MyCustomInput {...props} />
Button: ({ props }) => <MyCustomButton {...props} />
}}
>
<Counter />

Expand Down Expand Up @@ -55,8 +59,8 @@ Or you can customize the fallbacks on a per-component basis.
errorFallback={({ theme }) => (
<div
style={{
border: \`1px solid \${theme?.errorPrimary}\`,
color: theme?.errorPrimary,
border: \`1px solid \${theme?.borderError}\`,
color: theme?.textErrorPrimary,
padding: '1rem'
}}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ArgTypes, Meta } from '@storybook/blocks'
import * as DateRangeOptionsPropsStories from '../../../../../packages/ui-kit/src/components/TimeRangePicker/DateRangeOptionsProps.stories'

<Meta title="API/DateRangeOptionsProps" of={DateRangeOptionsPropsStories} />

# `DateRangeOptionsProps`

<ArgTypes of={DateRangeOptionsPropsStories.Primary} sort="alpha" />
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import * as SimpleFilterQueryPropsStories from '../../../../../packages/ui-kit/s

# SimpleFilter Overview

The SimpleFilter component is a dropdown designed to build metric filters and supply them to the components in
your dashboard. You can either use it in `static` mode by providing a set of `options` and a `columnName` that the
component can use to build the filter, or use it in `connected` mode by providing a `query` object which uses
The SimpleFilter component is a dropdown designed to build metric filters and supply them to the components in your
dashboard. You can either use it in `static` mode by providing a set of `options` and a `columnName` that the component
can use to build the filter, or use it in `connected` mode by providing a `query` object which uses
[Propel's Top Values API](https://www.propeldata.com/docs/query-your-data/top-values) to populate the dropdown.

## Basic usage
Expand All @@ -22,7 +22,7 @@ components. All the components wrapped within the same `FilterProvider` will sha

You can import the component in your React file and use it as shown in the following example:

<SourceCode of={SimpleFilterStories.ConnectedStory} shown />
<SourceCode of={SimpleFilterStories.SingleStory} shown />

## Props API

Expand Down
53 changes: 53 additions & 0 deletions app/storybook/documentation/ui-kit/components/TimeRangePicker.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ArgTypes, Meta, Source } from '@storybook/blocks'
import LinkTo from '@storybook/addon-links/react'
import { prettier } from '../../../src/utils'
import { SourceCode } from '../../../.storybook/blocks/SourceCode'
import * as TimeRangePickerStories from '../../../../../packages/ui-kit/src/components/TimeRangePicker/TimeRangePicker.stories'
import * as DateRangeOptionsPropsStories from '../../../../../packages/ui-kit/src/components/TimeRangePicker/DateRangeOptionsProps.stories'

<Meta title="Components/TimeRangePicker" of={TimeRangePickerStories} />

# TimeRangePicker overview

The `TimeRangePicker` component is a versatile tool for selecting date ranges within your front-end applications. It
allows users to pick a predefined time range, a custom date range, or a dynamic period up to the current date, with
additional settings to fine-tune the selection such as last `n`-days. Features include disabling specific options and a
fully controllable state via props.

## Basic usage

You can import the component in your React file and use it as shown in the following example:

<SourceCode of={TimeRangePickerStories.DefaultStory} />

<Source
language="tsx"
format="dedent"
dark
code={`
import { TimeRangePicker } from "@propeldata/ui-kit"

function App() {
return (
<TimeRangePicker />
);
}

`} />

## Props API

The following table describes the props available for the TimeRangePicker component:

<ArgTypes of={TimeRangePickerStories.DefaultStory} sort="alpha" />

### `DateRangeOptionsProps`

<ArgTypes of={DateRangeOptionsPropsStories.Primary} sort="alpha" />

See the documentation below for a complete reference to all of the props and classes available to the components
mentioned here.

- <LinkTo kind="API/DateRangeOptionsProps" story="overview">
DateRangeOptionsProps
</LinkTo>
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Counter, RelativeTimeRange } from '@propeldata/ui-kit'
import { Counter } from '@propeldata/ui-kit'
import React from 'react'
import { DashboardCommonProps } from '../../shared.types'
import { ConnectedComponentProps } from '../../shared.types'

export const CounterConnected = ({ envs: { REACT_APP_METRIC_UNIQUE_NAME_1 } }: DashboardCommonProps) => {
export const CounterConnected = ({ envs: { REACT_APP_METRIC_UNIQUE_NAME_1 }, timeRange }: ConnectedComponentProps) => {
const [fontColor, setFontColor] = React.useState('#101828')
const [refetchInterval, setRefetchInterval] = React.useState<number | undefined>(undefined)

Expand All @@ -18,10 +18,7 @@ export const CounterConnected = ({ envs: { REACT_APP_METRIC_UNIQUE_NAME_1 } }: D
card
query={{
metric: REACT_APP_METRIC_UNIQUE_NAME_1,
timeRange: {
relative: RelativeTimeRange.LastNDays,
n: 30
},
timeRange,
refetchInterval,
retry: false
}}
Expand Down
35 changes: 24 additions & 11 deletions packages/examples/dashboard/src/components/Dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
RelativeTimeRange,
SimpleFilter,
ThemeProvider,
TimeRangePicker,
DateRangeOptionsProps,
useTheme
} from '@propeldata/ui-kit'
import React from 'react'
Expand All @@ -21,7 +23,7 @@ import { TimeSeriesStatic } from '../TimeSeriesStatic'
const GlobalStyles = () => {
const theme = useTheme()
if (document && theme) {
document.body.style.setProperty('--bg-color', theme.bgSecondary as string)
document.body.style.setProperty('--bg-color', theme.backgroundSecondary as string)
}
return null
}
Expand All @@ -32,6 +34,10 @@ interface DashboardProps extends DashboardCommonProps {

export const Dashboard = ({ fetchToken, envs }: DashboardProps) => {
const [theme, setTheme] = React.useState<DefaultThemes>('lightTheme')
const [timeRange, setTimeRange] = React.useState<DateRangeOptionsProps | undefined>({
value: 'last-90-days'
})

return (
<AccessTokenProvider fetchToken={fetchToken}>
<FilterProvider>
Expand All @@ -44,15 +50,17 @@ export const Dashboard = ({ fetchToken, envs }: DashboardProps) => {
)}
>
<GlobalStyles />
<main style={{ color: 'var(--propel-text-secondary)', backgroundColor: 'var(--propel-bg-secondary)' }}>
<main
style={{ color: 'var(--propel-text-secondary)', backgroundColor: 'var(--propel-background-secondary)' }}
>
<h1 className="px-6 py-3 text-3xl">
React {React.version} Testing App
<button className="m-3" onClick={() => setTheme(theme === 'lightTheme' ? 'darkTheme' : 'lightTheme')}>
{theme === 'lightTheme' ? '🌚' : '🌞'}
</button>
</h1>
<hr />
<div className="px-6 py-3 w-full flex justify-end">
<div className="px-6 py-3 w-full flex justify-between">
<SimpleFilter
query={{
columnName: envs.REACT_APP_DIMENSION_1,
Expand All @@ -62,16 +70,21 @@ export const Dashboard = ({ fetchToken, envs }: DashboardProps) => {
}}
autocompleteProps={{ containerStyle: { width: '500px' }, placeholder: 'Filter by taco name' }}
/>
<TimeRangePicker value={timeRange} onChange={setTimeRange} />
</div>
<div className="grid grid-cols-2 gap-2">
<TimeSeriesStatic />
<TimeSeriesConnected envs={envs} />
<LeaderboardStatic />
<LeaderboardConnected envs={envs} />
<CounterStatic />
<CounterConnected envs={envs} />
<PieChartStatic />
<PieChartConnected envs={envs} />
{timeRange?.value && (
<>
<TimeSeriesStatic />
<TimeSeriesConnected envs={envs} timeRange={timeRange?.params} />
<LeaderboardStatic />
<LeaderboardConnected envs={envs} timeRange={timeRange?.params} />
<CounterStatic />
<CounterConnected envs={envs} timeRange={timeRange?.params} />
<PieChartStatic />
<PieChartConnected envs={envs} timeRange={timeRange?.params} />
</>
)}
</div>
</main>
</ThemeProvider>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import { Leaderboard, RelativeTimeRange, LeaderboardChartVariant } from '@propeldata/ui-kit'
import { Leaderboard, LeaderboardChartVariant } from '@propeldata/ui-kit'
import React from 'react'
import { DashboardCommonProps } from '../../shared.types'
import { ConnectedComponentProps } from '../../shared.types'

export const LeaderboardConnected = ({
envs: {
REACT_APP_METRIC_UNIQUE_NAME_1,
REACT_APP_DIMENSION_1 = '',
REACT_APP_DIMENSION_2 = '',
REACT_APP_DIMENSION_3 = ''
}
}: DashboardCommonProps) => {
},
timeRange: timeRangeProp
}: ConnectedComponentProps) => {
const [barsColor, setBarsColor] = React.useState('#75BFFF')
const [chartType, setChartType] = React.useState<LeaderboardChartVariant>('bar')
const [refetchInterval, setRefetchInterval] = React.useState<number | undefined>(undefined)
const [n, SetN] = React.useState<number>(30)
const [timeRange, setTimeRange] = React.useState(timeRangeProp)

React.useEffect(() => {
setTimeRange(timeRangeProp)
}, [timeRangeProp])

const handleSwitchRefetchInterval = () => {
setRefetchInterval(refetchInterval ? undefined : 1000)
Expand All @@ -39,10 +44,7 @@ export const LeaderboardConnected = ({
],
metric: REACT_APP_METRIC_UNIQUE_NAME_1,
rowLimit: 8,
timeRange: {
relative: RelativeTimeRange.LastNDays,
n
},
timeRange,
refetchInterval,
retry: false
}}
Expand Down Expand Up @@ -76,8 +78,8 @@ export const LeaderboardConnected = ({
<button className="border-2 p-1 h-9" onClick={handleSwitchRefetchInterval}>
Refetch Interval: {refetchInterval ? 'On 1000ms' : 'Off'}
</button>
<button className="border-2 p-1 h-9" onClick={() => SetN(n === 0 ? 30 : 0)}>
No data: {n === 0 ? 'On' : 'Off'}
<button className="border-2 p-1 h-9" onClick={() => setTimeRange({ n: 0 })}>
No data: {timeRange?.n ? 'On' : 'Off'}
</button>
sashathor marked this conversation as resolved.
Show resolved Hide resolved
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { PieChart, PieChartVariant, RelativeTimeRange } from '@propeldata/ui-kit'
import { PieChart, PieChartVariant } from '@propeldata/ui-kit'
import React from 'react'
import { DashboardCommonProps } from '../../shared.types'
import { ConnectedComponentProps } from '../../shared.types'

export const PieChartConnected = ({
envs: { REACT_APP_METRIC_UNIQUE_NAME_1, REACT_APP_DIMENSION_1 = '' }
}: DashboardCommonProps) => {
envs: { REACT_APP_METRIC_UNIQUE_NAME_1, REACT_APP_DIMENSION_1 = '' },
timeRange: timeRangeProp
}: ConnectedComponentProps) => {
const [chartType, setChartType] = React.useState<PieChartVariant>('pie')
const [refetchInterval, setRefetchInterval] = React.useState<number | undefined>(undefined)
const [n, SetN] = React.useState<number>(90)
const [timeRange, setTimeRange] = React.useState(timeRangeProp)

React.useEffect(() => {
setTimeRange(timeRangeProp)
}, [timeRangeProp])

const handleSwitchRefetchInterval = () => {
setRefetchInterval(refetchInterval ? undefined : 1000)
Expand All @@ -25,10 +30,7 @@ export const PieChartConnected = ({
},
metric: REACT_APP_METRIC_UNIQUE_NAME_1,
rowLimit: 8,
timeRange: {
relative: RelativeTimeRange.LastNDays,
n
},
timeRange,
refetchInterval,
retry: false,
filters: []
Expand All @@ -48,8 +50,8 @@ export const PieChartConnected = ({
<button className="border-2 p-1 h-9" onClick={handleSwitchRefetchInterval}>
Refetch Interval: {refetchInterval ? 'On 1000ms' : 'Off'}
</button>
<button className="border-2 p-1 h-9" onClick={() => SetN(n === 0 ? 30 : 0)}>
No data: {n === 0 ? 'On' : 'Off'}
<button className="border-2 p-1 h-9" onClick={() => setTimeRange({ n: 0 })}>
No data: {timeRange?.n ? 'On' : 'Off'}
</button>
</div>
</div>
Expand Down
Loading
Loading