Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion packages/ui-dashboard/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": false,
"name": "@sentio/ui-dashboard",
"version": "0.2.0",
"version": "0.2.1",
"description": "Dashboard UI components for the Sentio platform, decoupled from backend services.",
"exports": {
".": {
Expand Down
3 changes: 3 additions & 0 deletions packages/ui-dashboard/src/charts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export { ChartLegend } from './ChartLegend'
// Refresh affordance
export { RefreshContext, RefreshButton } from './RefreshContext'

// Option panels
export * from './options'

// Theme
export { sentioColors } from './theme/sentio-colors'
export { sentioTheme, sentioThemeDark } from './theme/sentio-theme'
Expand Down
163 changes: 163 additions & 0 deletions packages/ui-dashboard/src/charts/options/BarGaugeControls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { produce } from 'immer'
import { defaults } from 'lodash'
import { DisclosurePanel } from '@sentio/ui-core'
import type {
BarGaugeConfigLike,
CalculationLike,
DirectionLike,
SortByLike
} from '../../types'

interface Props {
config?: BarGaugeConfigLike
defaultOpen?: boolean
onChange: (config: BarGaugeConfigLike) => void
}

export const defaultConfig: BarGaugeConfigLike = {
direction: 'HORIZONTAL',
calculation: 'LAST',
sort: {
sortBy: 'ByName',
orderDesc: true
}
}

const directionItems = [
{ label: 'Horizontal', value: 'HORIZONTAL' },
{ label: 'Vertical', value: 'VERTICAL' }
]

const CalculationItems = [
{ label: 'Last', value: 'LAST' },
{ label: 'First', value: 'FIRST' },
{ label: 'Total', value: 'TOTAL' },
{ label: 'Mean', value: 'MEAN' },
{ label: 'Max', value: 'MAX' },
{ label: 'Min', value: 'MIN' }
]

const sortByItems = [
{ label: 'Name', value: 'ByName' },
{ label: 'Value', value: 'ByValue' }
]

const orderItems = [
{ label: 'Ascendant', value: 'false' },
{ label: 'Descendant', value: 'true' }
]

export function BarGaugeControls({ config, defaultOpen, onChange }: Props) {
config = defaults(config, defaultConfig)

function onCalculationChange(cal: CalculationLike) {
config &&
onChange(produce(config, (draft) => void (draft.calculation = cal)))
}

function onDirectionChange(dir: DirectionLike) {
config && onChange(produce(config, (draft) => void (draft.direction = dir)))
}

function onOrderChange(orderDesc: boolean) {
config &&
onChange(
produce(config, (draft) => {
draft.sort = draft.sort || {}
draft.sort.orderDesc = orderDesc
})
)
}

function onSortByChange(sortBy: SortByLike) {
config &&
onChange(
produce(config, (draft) => {
draft.sort = draft.sort || {}
draft.sort.sortBy = sortBy
})
)
}

return (
<DisclosurePanel
title="Bar Gauge Options"
defaultOpen={defaultOpen}
containerClassName="w-full bg-default-bg"
>
<div className="flex items-center gap-4">
<div className="shadow-xs flex rounded-md">
<span className="sm:text-ilabel border-main inline-flex items-center rounded-l-md border bg-gray-50 px-3 ">
Direction
</span>
<select
value={config.direction}
className="sm:text-ilabel border-main text-text-foreground inline-flex items-center rounded-r-md border border-l-0 pl-4 pr-7"
onChange={(e) => onDirectionChange(e.target.value as DirectionLike)}
>
{directionItems.map((d) => {
return (
<option key={d.value} value={d.value}>
{d.label}
</option>
)
})}
</select>
</div>

<div className="shadow-xs flex rounded-md">
<span className="sm:text-ilabel border-main inline-flex items-center rounded-l-md border bg-gray-50 px-3 ">
Calculation
</span>
<select
value={config.calculation}
className="sm:text-ilabel border-main text-text-foreground inline-flex items-center rounded-r-md border border-l-0 pl-4 pr-7"
onChange={(e) =>
onCalculationChange(e.target.value as CalculationLike)
}
>
{CalculationItems.map((d) => {
return (
<option key={d.value} value={d.value}>
{d.label}
</option>
)
})}
</select>
</div>

<div className="shadow-xs flex rounded-md">
<span className="sm:text-ilabel border-main inline-flex items-center whitespace-nowrap rounded-l-md border bg-gray-50 px-3">
Sort by
</span>
<select
value={config?.sort?.sortBy}
className="sm:text-ilabel border-main text-text-foreground inline-flex items-center border border-l-0 pl-4 pr-7"
onChange={(e) => onSortByChange(e.target.value as SortByLike)}
>
{sortByItems.map((d) => {
return (
<option key={d.value} value={d.value}>
{d.label}
</option>
)
})}
</select>
<select
value={config?.sort?.orderDesc + ''}
className="sm:text-ilabel border-main text-text-foreground inline-flex items-center rounded-r-md border border-l-0 pl-4 pr-7"
onChange={(e) => onOrderChange(e.target.value === 'true')}
>
{orderItems.map((d) => {
return (
<option key={d.label} value={d.value + ''}>
{d.label}
</option>
)
})}
</select>
</div>
</div>
</DisclosurePanel>
)
}
108 changes: 108 additions & 0 deletions packages/ui-dashboard/src/charts/options/LabelControls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { useEffect, useMemo } from 'react'
import { produce } from 'immer'
import { Button as NewButton, DisclosurePanel, HelpIcon } from '@sentio/ui-core'
import type { LabelConfigLike } from '../../types'

interface Props {
config?: LabelConfigLike
setConfig: (value: LabelConfigLike) => void
defaultOpen?: boolean
}

const initialConfig: LabelConfigLike = {
columns: [],
alias: ''
}

export const LabelControls = ({ config, setConfig, defaultOpen }: Props) => {
// Migrate existing columns config to alias on component mount
useEffect(() => {
if (config?.columns && config.columns.length > 0 && !config.alias) {
const aliasParts: string[] = []
config.columns.forEach((colConfig) => {
if (!colConfig.name) return // Skip if name is undefined

if (colConfig.showLabel === false && colConfig.showValue === false) {
// ignore
} else if (colConfig.showValue === false) {
aliasParts.push(colConfig.name)
} else {
aliasParts.push(`{{${colConfig.name}}}`)
}
})

if (aliasParts.length > 0) {
const migratedAlias = aliasParts.join(', ')
setConfig(
produce(config, (draft) => {
draft.alias = migratedAlias
draft.columns = [] // Clear the old columns config
})
)
}
}
}, [config, setConfig])

const onAliasChanged = (alias: string) => {
setConfig(
produce(config ?? initialConfig, (draft) => {
draft.alias = alias
})
)
}

const _defaultOpen = useMemo(() => {
if (defaultOpen) {
return true
}
return (
config?.alias !== '' || (config?.columns && config.columns.length > 0)
)
}, [config, defaultOpen])

return (
<DisclosurePanel
title="Label Controls"
defaultOpen={_defaultOpen}
containerClassName="w-full bg-default-bg"
>
<div className="flex items-center gap-2">
<div className="inline-flex h-8">
<span className="sm:text-icontent border-main inline-flex items-center rounded-l-md border border-r-0 bg-gray-50 px-2 font-medium">
Label Alias
<HelpIcon
text={
<div className="text-icontent text-text-foreground">
<div>Series name override or template.</div>
<div>
Ex.{' '}
<span className="text-primary mx-1 font-semibold italic">
{'{{contract}}'}
</span>{' '}
will be replaced with the value of the contract label.
</div>
</div>
}
/>
</span>
<input
type="text"
value={config?.alias || ''}
onChange={(e) => onAliasChanged(e.target.value)}
placeholder="Enter alias..."
className="focus:border-primary-500 sm:text-icontent border-main inline-flex w-64 items-center rounded-r-md border px-2"
/>
</div>
<NewButton
type="button"
role="link"
onClick={() => {
setConfig(initialConfig)
}}
>
Reset
</NewButton>
</div>
</DisclosurePanel>
)
}
54 changes: 54 additions & 0 deletions packages/ui-dashboard/src/charts/options/LineControls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { produce } from 'immer'
import {
DisclosurePanel,
NewButtonGroup as ButtonGroup,
Checkbox
} from '@sentio/ui-core'
import type { LineConfigLike, LineStyleLike } from '../../types'

const lineStyles: { label: string; value: LineStyleLike }[] = [
{ label: 'Solid', value: 'Solid' },
{ label: 'Dotted', value: 'Dotted' }
]

interface Props {
config?: LineConfigLike
defaultOpen?: boolean
onChange: (config: LineConfigLike) => void
}

export const LineControls = ({ config, defaultOpen, onChange }: Props) => {
const setStyle = (style: LineStyleLike) => {
onChange(
produce(config || {}, (draft) => {
draft.style = style
})
)
}
const setSmooth = (smooth: boolean) => {
onChange(
produce(config || {}, (draft) => {
draft.smooth = smooth
})
)
}
return (
<DisclosurePanel
title="Line style"
containerClassName="w-full bg-default-bg"
>
<div className="flex items-center gap-4">
<ButtonGroup
buttons={lineStyles}
value={config?.style || 'Solid'}
onChange={setStyle}
/>
<Checkbox
label="Smooth Curves"
checked={config?.smooth}
onChange={setSmooth}
/>
</div>
</DisclosurePanel>
)
}
Loading
Loading