Skip to content

Commit

Permalink
feat(ui): add dark mode (#195)
Browse files Browse the repository at this point in the history
* accessibility improvements

* charts colors and layout

* merge fix

* reduce not needed madding and margins

* removed unnecessary margins

* removed unnecessary margins

* feat: add dark mode redux actions

* data ink optimization

* fix: add missing actions

* added switch dark mode

* fix: add missing actions

* charts splitline opacity

* various fixes

* feat: add dark mode and light mode buttons

* fix accessibility WIP

* sider-bk image

* feat: add button in all the pages

* fix: useLayoutConfiguration

* spaces fix

* fix: header

* fix: icon position

* fix: add anchor

* fix: copy

* charts readability

* fix: padding logo

* fix launchpad chart readability

* Merge branch 'dark-mode' of https://github.com/radicalbit/radicalbit-ai-monitoring into dark-mode

* fix legend

* table color

* add legend on datapoint distribution chart

* feat: remove unseless file

* feat(ui): add new version of @radicalbit/radicalbit-design-system

* feat(ui): fix dark mode legend on some charts

* feat(ui): fix axis label of confusionMatrix

* little fixes

* icon size fix

* feat: remove obsolete less styles

---------

Co-authored-by: cybermarinella <marinella.mastrosimone@gmail.com>
Co-authored-by: Luca Tagliabue <luca.tagliabue@radicalbit.io>
  • Loading branch information
3 people authored Nov 15, 2024
1 parent 0eec4a9 commit 1c3bc31
Show file tree
Hide file tree
Showing 86 changed files with 586 additions and 309 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ services:
retries: 2

docker-client:
image: docker:cli
image: docker:27.2.1-cli
command: "/bin/sh -c 'docker build ./spark -t radicalbit-spark-py:develop && docker save radicalbit-spark-py:develop -o /images/radicalbit-spark-py:develop.tar'"
environment:
DOCKER_TLS_CERTDIR: /certs
Expand Down
2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@grafana/faro-react": "^1.8.2",
"@radicalbit/formbit": "1.0.0",
"@radicalbit/radicalbit-design-system": "^1.2.0",
"@radicalbit/radicalbit-design-system": "^1.3.0",
"@reduxjs/toolkit": "^2.2.4",
"@vitejs/plugin-react": "^4.2.1",
"ace-builds": "^1.33.2",
Expand Down
9 changes: 5 additions & 4 deletions ui/src/components/Logo/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import { useSelector } from 'react-redux';

const {
selectHasLeftColumnCollapsed,
selectIsAllDark,
selectHasHeaderLeftContentDark,
} = layoutSelectors;

export default function Logo({ onClick, title }) {
export default function Logo({ className = '', onClick, title }) {
const hasLeftColumnCollapsed = useSelector(selectHasLeftColumnCollapsed);
const isAllDark = useSelector(selectIsAllDark);
const hasHeaderLeftContentDark = useSelector(selectHasHeaderLeftContentDark);

const shape = hasLeftColumnCollapsed ? 'collapsed' : 'expanded';
const color = isAllDark ? 'light' : 'dark';
const color = hasHeaderLeftContentDark ? 'dark' : 'light';

const logos = {
expanded: {
Expand All @@ -31,6 +31,7 @@ export default function Logo({ onClick, title }) {

return (
<a
className={`${className} p-4`}
onClick={onClick}
role="presentation"
title={title}
Expand Down
7 changes: 5 additions & 2 deletions ui/src/components/charts/line-chart/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ export default function lineChartOptions(title, color, currentDataset, reference
...commonChartOptions.seriesOptions(CHART_TYPE.LINE, 'Reference', CHART_COLOR.REFERENCE, referenceDatasetFormatted),
endLabel: {
show: true,
color: CHART_COLOR.REFERENCE,
color: CHART_COLOR.REFERENCE_LIGHT,
formatter: ({ value }) => `${value[1]}`,
},
color: CHART_COLOR.REFERENCE,
color: CHART_COLOR.REFERENCE_LIGHT,
};

referenceLine.lineStyle.type = 'dotted';
Expand All @@ -36,6 +36,9 @@ export default function lineChartOptions(title, color, currentDataset, reference
series,
legend: {
show: true,
textStyle: {
color: CHART_COLOR.REFERENCE_LIGHT,
},
right: 0,
},
};
Expand Down
27 changes: 16 additions & 11 deletions ui/src/components/charts/pie-chart/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,24 @@ echarts.use([
]);

function PieChart({ title, data }) {
const splittedTitle = title.split(' ');
const currentData = numberFormatter({ maximumSignificantDigits: 4 }).format(data * 100);

if (data <= 0) {
return (
<div className="flex flex-row items-center gap-2">
<div className="flex flex-row items-center">
<EmptyPieChart />

<Label splittedTitle={splittedTitle} />
<Label percentage={currentData} title={title} />

</div>
);
}

return (
<div className="flex flex-row items-center gap-2">
<div className="flex flex-row items-center">
<EvaluatedPieChart data={data} />

<Label splittedTitle={splittedTitle} />
<Label percentage={currentData} title={title} />
</div>
);
}
Expand All @@ -55,7 +56,7 @@ function EmptyPieChart() {
echarts={echarts}
onChartReady={handleOnChartReady}
option={pieChartOptions({ currentData: 0, referenceData: 100 })}
style={{ height: '8rem', width: '100%' }}
style={{ height: '8rem', width: '10rem' }}
/>
);
}
Expand All @@ -74,17 +75,21 @@ function EvaluatedPieChart({ data }) {
echarts={echarts}
onChartReady={handleOnChartReady}
option={pieChartOptions({ currentData, referenceData })}
style={{ height: '8rem', width: '100%' }}
style={{ height: '8rem', width: '10rem' }}
/>
);
}

function Label({ splittedTitle }) {
function Label({ title, percentage }) {
return (
<div className="flex flex-col items-start justify-center">
<p className="font-bold text-3xl" style={{ marginBottom: '-0.6rem' }}>{splittedTitle[0]}</p>
<div className="flex flex-col items-start justify-center w-full">
<h1 className="font-bold text-3xl" style={{ marginBottom: '-0.25rem' }}>
{percentage}

<small className="font-normal">%</small>
</h1>

<p className="m-0 text-2xl tracking-wider">{splittedTitle[1]}</p>
<h2 className="m-0 text-lg font-normal">{title}</h2>
</div>
);
}
Expand Down
11 changes: 2 additions & 9 deletions ui/src/components/charts/pie-chart/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,12 @@ export default function pieChartOptions({ currentData, referenceData }) {
name: 'Current',
itemStyle: { color: CHART_COLOR.CURRENT },
selected: true,
label: {
show: true,
fontSize: '14',
fontWeight: 'bold',
color: CHART_COLOR.WHITE,
position: 'center',
formatter: ({ data: { value } }) => value === 0 ? '--' : `${value}%`,
},
label: { show: false },
},
{
value: referenceData,
name: 'Reference',
itemStyle: { color: referenceData === 100 ? '#1e2b43' : '#f60000' },
itemStyle: { color: referenceData === 100 ? '#9b99a1' : '#f60000' },
label: { show: false },
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function Body() {
const tabs = useGetTabs();

return (
<div className="flex flex-col gap-4 h-full">
<div className="flex flex-col gap-4 p-4 h-full">
<div className="px-4 pt-4 h-[99%]">
<Tabs
activeKey={activeTab}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/container/app/bottom-menu/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function BottomMenu() {
const items = [
{
key: 'Documentation',
title: 'Documentation',

label: (
<>
<span className="anticon"><FontAwesomeIcon icon={faCircleQuestion} /></span>
Expand Down
22 changes: 8 additions & 14 deletions ui/src/container/app/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import SiderBk from '@Img/sider-bk.png';
import Logo from '@Src/components/Logo';
import ModalsProvider from '@Src/components/modals/modals-provider';
import { useContextConfigurationFromUrlEffect } from '@State/context-configuration/hooks';
import { useNotification } from '@State/notification/hooks';
import { actions as layoutActions, selectors as layoutSelectors } from '@State/layout';
import { useNotification } from '@State/notification/hooks';
import '@Styles/index.less';
import '@Styles/tailwind.less';
import { Layout } from '@radicalbit/radicalbit-design-system';
import CookieConsent from 'react-cookie-consent';
import { useDispatch, useSelector } from 'react-redux';
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
import { createRoutes } from '../layout';
import { useLayoutProvider } from '../layout/layout-provider';
import BottomMenu from './bottom-menu';
import MainHeaderContentSwitch from './content-switch/header';
import SecondaryContentSwitch from './content-switch/secondary-column/content';
Expand All @@ -22,23 +21,19 @@ export default function App() {
const navigate = useNavigate();
const { pathname } = useLocation();

useLayoutProvider();

useNotification();
useContextConfigurationFromUrlEffect();

const isAllDark = useSelector(layoutSelectors.selectIsAllDark);

const hasHeaderContentDark = useSelector(layoutSelectors.selectHasHeaderContentDark);

const isMainContentDark = useSelector(layoutSelectors.selectHasMainContentDark);
const hasMainContentDark = isAllDark || isMainContentDark;
const hasHeaderLeftContentDark = useSelector(layoutSelectors.selectHasHeaderLeftContentDark);
const hasHeaderSecondaryContentDark = useSelector(layoutSelectors.selectHasHeaderSecondaryContentDark);
const hasLeftContentDark = useSelector(layoutSelectors.selectHasLeftContentDark);
const hasMainContentDark = useSelector(layoutSelectors.selectHasMainContentDark);
const hasSecondaryContentDark = useSelector(layoutSelectors.selectHasSecondaryContentDark);

const hasHeader = useSelector(layoutSelectors.selectHasHeader);
const isSecondaryColumn = useSelector(layoutSelectors.selectHasSecondaryColumn);
const isLeftColumnCollapsed = useSelector(layoutSelectors.selectHasLeftColumnCollapsed);
const hasSecondaryContentDark = useSelector(layoutSelectors.selectHasSecondaryContentDark);
const hasHeaderSecondaryContentDark = useSelector(layoutSelectors.selectHasHeaderSecondaryContentDark);
const hasSecondaryColumnCollapsed = useSelector(layoutSelectors.selectHasSecondaryColumnCollapsed);

const hasSecondaryColumn = isSecondaryColumn;
Expand All @@ -64,7 +59,6 @@ export default function App() {

return (
<>

<Layout
hasHeader={hasHeader}
hasLeftColumn
Expand All @@ -73,9 +67,9 @@ export default function App() {
hasRightColumn={false}
hasSecondaryColumn={hasSecondaryColumn}
left={{
hasHeaderLeftContentDark: true,
hasHeaderLeftContentDark,
hasLeftColumnCollapsed,
hasLeftContentDark: true,
hasLeftContentDark,
leftColumnHeaderAltContent: <Logo onClick={goToHomePage} title="Radicalbit" />,
backgroundImage: SiderBk,
mainMenu: createRoutes({ currentPath: pathname }),
Expand Down
18 changes: 3 additions & 15 deletions ui/src/container/launchpad/central-row/columns.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,7 @@ export const getColumns = (
const value = percentages?.dataQuality.value;
const data = (value && value !== -1) ? `${numberFormatter({ maximumSignificantDigits: 4 }).format(parseFloat(value) * 100)}%` : '--';

return (
<div>
{data}
</div>
);
return data;
},
}),

Expand All @@ -73,11 +69,7 @@ export const getColumns = (
const value = percentages?.modelQuality.value;
const data = (value && value !== -1) ? `${numberFormatter({ maximumSignificantDigits: 4 }).format(parseFloat(value) * 100)}%` : '--';

return (
<div>
{data}
</div>
);
return data;
},
}),

Expand All @@ -92,11 +84,7 @@ export const getColumns = (
const value = percentages?.drift.value;
const data = (value && value !== -1) ? `${numberFormatter({ maximumSignificantDigits: 4 }).format(parseFloat(value) * 100)}%` : '--';

return (
<div>
{data}
</div>
);
return data;
},
}),

Expand Down
57 changes: 52 additions & 5 deletions ui/src/container/launchpad/header.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,64 @@
import { NewHeader, SectionTitle } from '@radicalbit/radicalbit-design-system';
import {
MAIN_LAYOUT_DARK_MODE_CONFIGURATION,
MAIN_LAYOUT_LIGHT_MODE_CONFIGURATION,
} from '@Container/layout/layout-provider/layout-provider-configuration';
import { faMoon, faSun } from '@fortawesome/free-solid-svg-icons';
import {
FontAwesomeIcon, NewHeader, SectionTitle, Tooltip,
} from '@radicalbit/radicalbit-design-system';
import { useState } from 'react';
import { useDispatch } from 'react-redux';

export default function MainListModelsHeader() {
const title = 'AI Monitoring Launchpad';
const subtitle = 'a comprehensive dashboard to track model performance, access setup resources, review alerts and ensure data completeness.';

return (
<NewHeader
actions={{
one: <DarkMode />,
two: <div style={{ width: '1rem', height: '1rem' }} />,
}}
title={(
<SectionTitle
subtitle={subtitle}
title={title}
/>
<>
<h1>{title}</h1>

<SectionTitle subtitle={subtitle} />
</>
)}
/>
);
}

function DarkMode() {
const dispatch = useDispatch();
const [isDarkMode, setIsDarkMode] = useState(!!window.localStorage.getItem('enable-dark-mode'));

const handleOnEnableDarkMode = () => {
window.localStorage.setItem('enable-dark-mode', true);
setIsDarkMode(true);

MAIN_LAYOUT_DARK_MODE_CONFIGURATION.forEach((action) => dispatch(action()));
};

const handleOnEnableLightMode = () => {
window.localStorage.removeItem('enable-dark-mode');
setIsDarkMode(false);

MAIN_LAYOUT_LIGHT_MODE_CONFIGURATION.forEach((action) => dispatch(action()));
};

if (isDarkMode) {
return (
<Tooltip title="Switch to light mode">
<FontAwesomeIcon icon={faMoon} onClick={handleOnEnableLightMode} />
</Tooltip>
);
}

return (
<Tooltip title="Switch to dark mode">
<FontAwesomeIcon icon={faSun} onClick={handleOnEnableDarkMode} />
</Tooltip>
);
}
4 changes: 4 additions & 0 deletions ui/src/container/launchpad/index.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { MAIN_LAYOUT_DARK_MODE_CONFIGURATION, MAIN_LAYOUT_LIGHT_MODE_CONFIGURATION } from '@Container/layout/layout-provider/layout-provider-configuration';
import useSetDarkMode from '@Hooks/use-set-dark-mode';
import ModelStatsList from './central-row';
import RightColumn from './right-column';
import TopRow from './top-row';

export default function Launchpad() {
useSetDarkMode(MAIN_LAYOUT_DARK_MODE_CONFIGURATION, MAIN_LAYOUT_LIGHT_MODE_CONFIGURATION);

return (
<div className="flex flex-col p-4 gap-4 h-full">
<TopRow />
Expand Down
Loading

0 comments on commit 1c3bc31

Please sign in to comment.