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

feat: Add dashboard text blocks #1913

Draft
wants to merge 102 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
192afb8
refactor: Clean up
bprusinowski Nov 25, 2024
8f1d155
refactor: Do not use default export
bprusinowski Nov 26, 2024
52ded1b
fix: Ids
bprusinowski Nov 26, 2024
f100b05
feat: Set up LayoutBlocksConfigurator skeleton and translations
bprusinowski Nov 26, 2024
700dbea
refactor: Extract AddButton
bprusinowski Nov 26, 2024
8255398
feat: Add an "Add text" button + translations
bprusinowski Nov 26, 2024
3869fcd
feat: Only render LayoutBlocksConfigurator for dashboard canvas layout
bprusinowski Nov 26, 2024
9613d39
refactor: createChartId -> createId
bprusinowski Nov 26, 2024
433bbe2
feat: Add a way to add and remove text blocks
bprusinowski Nov 26, 2024
d2cd43a
chore: Update translations
bprusinowski Nov 26, 2024
cc1f593
refactor: Base dashboard rendering on blocks
bprusinowski Nov 28, 2024
2a022a3
chore: Update translations
bprusinowski Dec 11, 2024
9b1d978
feat: AddLayoutBlocks
bprusinowski Dec 11, 2024
763c9ca
chore: Add react-markdown
bprusinowski Dec 11, 2024
24d775d
feat: Use react-markdown for text blocks
bprusinowski Dec 11, 2024
086dd67
refactor: Rename
bprusinowski Dec 11, 2024
aa98692
feat: Add initial LayoutBlocksSelector
bprusinowski Dec 11, 2024
4b3e7f7
style: Put ellipsis after second line for main label in ControlTab
bprusinowski Dec 11, 2024
849cba7
feat: Better align block control tabs with the design
bprusinowski Dec 11, 2024
bc63fe9
feat: Make it possible to remove text blocks + align better with design
bprusinowski Dec 11, 2024
8a39e65
refactor: Extract useOrderedLocales
bprusinowski Dec 12, 2024
17ea8bb
feat: Add a way to edit text blocks content
bprusinowski Dec 12, 2024
510a672
feat: Text blocks can be defined per locale
bprusinowski Dec 12, 2024
913af1e
feat: Make theInput multiline
bprusinowski Dec 12, 2024
49b4773
feat: Make Title and Description Markdown-compatible
bprusinowski Dec 12, 2024
7d33f0e
refactor: Consolidate Markdown usage
bprusinowski Dec 12, 2024
a71c314
style: Use white background for ReactGridItems
bprusinowski Dec 12, 2024
3f38767
chore: Update MUI
bprusinowski Dec 16, 2024
0e917bb
chore: Update TypeScript
bprusinowski Dec 16, 2024
5609cc0
style: Keep vertical padding in textarea
bprusinowski Dec 16, 2024
c4a838d
fix: TypeScript errors
bprusinowski Dec 16, 2024
c774a2d
feat: Improve Markdown text styles
bprusinowski Dec 16, 2024
70e8b45
fix: Ignore MUI theme TypeScript errors
bprusinowski Dec 16, 2024
aa58351
fix: Use allowed fontWeight value
bprusinowski Dec 16, 2024
409b327
refactor: Extract to useStyles
bprusinowski Dec 16, 2024
22ddf0f
style: Remove border bottom from last child
bprusinowski Dec 16, 2024
90ffd13
style: Remove background
bprusinowski Dec 16, 2024
50539a0
feat: Open text block editing panel on text click
bprusinowski Dec 16, 2024
7946b01
style: Use pointer when makes sense
bprusinowski Dec 16, 2024
87aa433
chore: Add Markdown plugins
bprusinowski Dec 16, 2024
b70e864
feat: Add keydown handler for most popular actions (b, i, u)
bprusinowski Dec 16, 2024
9817df8
feat: Allow re-doing actions
bprusinowski Dec 16, 2024
dfc2a6d
refactor: Improve types
bprusinowski Dec 16, 2024
c213b11
chore: Only use one prettier
bprusinowski Dec 16, 2024
b925ac2
fix: Syntax TypeScript error
bprusinowski Dec 16, 2024
cb18a05
fix: Type issues
bprusinowski Dec 16, 2024
264bfa9
docs: Update CHANGELOG
bprusinowski Dec 16, 2024
4122bf3
chore: Add pull request template
bprusinowski Dec 16, 2024
df7177c
style: Improve styles
bprusinowski Dec 16, 2024
5f7f6ae
refactor: Apply class name directly in the component
bprusinowski Dec 16, 2024
76bd701
chore: Remove default text initialization
bprusinowski Dec 16, 2024
b61ebda
feat: Add a way to drag text blocks in free canvas layout
bprusinowski Dec 16, 2024
cfdeb3e
chore: Update translations
bprusinowski Dec 16, 2024
f7e734e
refactor: Improve types
bprusinowski Dec 16, 2024
655578e
feat: Improve ChartGridLayout
bprusinowski Dec 16, 2024
faf6de3
feat: Add initial auto-sizing text blocks logic
bprusinowski Dec 16, 2024
1b4e678
fix: Types
bprusinowski Dec 16, 2024
f785c91
chore: Update ts-jest
bprusinowski Dec 16, 2024
dac1c16
fix: Mocking Markdown packages in tests
bprusinowski Dec 16, 2024
57712ab
fix: Condition
bprusinowski Dec 16, 2024
a5fb414
refactor: Names
bprusinowski Dec 16, 2024
3774801
chore: Add translations
bprusinowski Dec 16, 2024
339ae7f
chore: Comments
bprusinowski Dec 16, 2024
cfb72f5
Merge branch 'main' of github.com:visualize-admin/visualization-tool …
bprusinowski Jan 13, 2025
5427ffd
chore: yarn.lock
bprusinowski Jan 13, 2025
bea97ee
chore: Downgrade TS
bprusinowski Jan 13, 2025
ccd8edc
chore: Remove not needed
bprusinowski Jan 13, 2025
9bb1efa
chore: Downgrade MUI
bprusinowski Jan 13, 2025
35adb71
chore: yarn.lock
bprusinowski Jan 13, 2025
a82521d
feat: Immediately open new text blocks
bprusinowski Jan 13, 2025
bff8cf4
feat: Ensure dashboard layout is correct when changing layout
bprusinowski Jan 14, 2025
cb90e16
feat: Update ensureDashboardLayoutIsCorrect to be based on blocks
bprusinowski Jan 14, 2025
26c0a9b
feat: Ensure blocks are in sync with reality
bprusinowski Jan 14, 2025
bc23c12
feat: Disable immer's autoFreeze
bprusinowski Jan 14, 2025
f028d32
feat: Improve default cell selection logic
bprusinowski Jan 14, 2025
a5ad3ad
fix: Displaying of text blocks in tall dashboard
bprusinowski Jan 14, 2025
80f5567
Merge branch 'main' of github.com:visualize-admin/visualization-tool …
bprusinowski Jan 14, 2025
c7987e6
feat: Sync text blocks' height across all breakpoints
bprusinowski Jan 14, 2025
8f106e9
chore: Add unlisted dependency to package.json
bprusinowski Jan 14, 2025
21c6bee
fix: Test
bprusinowski Jan 14, 2025
0f1feb7
feat: Show Objects panel for every dashboard type
bprusinowski Jan 14, 2025
fd2f8bc
feat: Only allow horizontal resizing for text blocks
bprusinowski Jan 14, 2025
5d275af
refactor: Extract ActionElementsContainer
bprusinowski Jan 14, 2025
400e7fa
fix: Remove not needed blocks from layouts
bprusinowski Jan 15, 2025
b3db438
feat: Add BlockMoreButton
bprusinowski Jan 15, 2025
e2afbe6
fix: Do not open panel when shouldn't
bprusinowski Jan 15, 2025
92e7f2c
feat: Add a CTA to empty text blocks
bprusinowski Jan 15, 2025
8cfb53d
style: Do not let ActionElementsContainer grow
bprusinowski Jan 15, 2025
504a555
fix: Stop event propagation
bprusinowski Jan 15, 2025
2f375d9
fix: Pass props to Markdown components
bprusinowski Jan 15, 2025
150383c
fix: Add missing dependency
bprusinowski Jan 15, 2025
f31be35
chore: Add @mdxeditor/editor
bprusinowski Jan 16, 2025
0ba61ac
feat: Add basic MarkdownInput
bprusinowski Jan 16, 2025
c42ba3d
style: Improve MarkdownInput margins
bprusinowski Jan 16, 2025
021be37
feat: Move label below toolbar
bprusinowski Jan 16, 2025
438627a
feat: Add and update icons
bprusinowski Jan 16, 2025
5d77b7c
feat: Add BlockTypeMenu
bprusinowski Jan 16, 2025
3a79377
refactor: Extract BlockTypeMenu to mdx-editor folder
bprusinowski Jan 16, 2025
2345dc2
refactor: Extract ToolbarIconButton
bprusinowski Jan 16, 2025
c0f145b
feat: Add custom BoldItalicUnderlineToggles
bprusinowski Jan 16, 2025
5f00f56
feat: Add custom ListToggles
bprusinowski Jan 16, 2025
7715db3
fix: Jest mocks
bprusinowski Jan 16, 2025
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
19 changes: 19 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!--- Link this pull request to an issue (fixes or closes #issue_number) -->

Closes #

<!--- Describe the changes -->

This PR...

<!--- Test instructions -->

## How to test

1. Go to...

<!--- Reproduction steps, in case of a bug -->

---

- [ ] Add a CHANGELOG entry
19 changes: 12 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ You can also check the
# Unreleased

- Features
- Implemented Content Security Policy (CSP)
- Added a new chart type - bar
- It's now possible to export charts as images
- Added support for custom colors in single and multi-colored charts, enabling enhanced visual customization.
- Introduced a new Color Picker, offering greater flexibility and precision in chart color selection.
- Added Footer to the Profile Page
- Added footer to the profile page
- Added support for custom colors in single and multi-colored charts, enabling
enhanced visual customization
- Introduced a new color picker, offering greater flexibility and precision in
chart color selection
- Fixes
- Addressed security flaw allowing the injection of arbitrary URLs
in the `sourceUrl` parameter in the GraphQL API
- Addressed security flaw allowing the injection of arbitrary URLs in the
`sourceUrl` parameter in the GraphQL API
- Color mapping is now correctly kept up to date in case of editing an old
chart and the cube has been updated in the meantime and contains new values
in the color dimension
Expand All @@ -34,6 +36,9 @@ You can also check the
inputs
- Opening a temporal dimension with timezone in table chart configurator
doesn't crash the application anymore
- Themes fetching is now done by using standard SPARQL iris (starting with
https://), so that it behaves consistently across different SPARQL database
engines
- Styles
- Updated dataset result borders to match the design
- Maintenance
Expand All @@ -49,14 +54,14 @@ You can also check the
- Removed unused dependencies and dead code
- Updated several outdated packages
- Added knip as a new CI task
- Implemented Content Security Policy (CSP)
- Performance
- Introduced sharding to improve performance of basic CI checks (unit tests,
type checks, linting, knip)
- Docs
- Added auto-generated JSON Schema files for configurator state and chart
config and improved preview charts via API documentation


# [5.0.2] - 2024-11-28

- Features
Expand Down
4 changes: 2 additions & 2 deletions app/charts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ import {
import { theme } from "@/themes/federal";
import { bfs } from "@/utils/bfs";
import { CHART_CONFIG_VERSION } from "@/utils/chart-config/constants";
import { createChartId } from "@/utils/create-chart-id";
import { createId } from "@/utils/create-id";
import { isMultiHierarchyNode } from "@/utils/hierarchy";
import { unreachableError } from "@/utils/unreachable";

Expand Down Expand Up @@ -374,7 +374,7 @@ export const getInitialConfig = (
activeField: string | undefined;
} => {
return {
key: key ?? createChartId(),
key: key ?? createId(),
version: CHART_CONFIG_VERSION,
meta: meta ?? META,
// Technically, we should scope filters per cube; but as we only set initial
Expand Down
23 changes: 23 additions & 0 deletions app/components/action-elements-container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Theme } from "@mui/material";
import { makeStyles } from "@mui/styles";
import { ReactNode } from "react";

const useStyles = makeStyles<Theme>((theme) => ({
root: {
display: "flex",
alignItems: "center",
gap: theme.spacing(2),
height: "fit-content",
marginTop: "-0.33rem",
},
}));

export const ActionElementsContainer = ({
children,
}: {
children: ReactNode;
}) => {
const classes = useStyles();

return <div className={classes.root}>{children}</div>;
};
22 changes: 22 additions & 0 deletions app/components/add-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Button, ButtonProps } from "@mui/material";

import { Icon } from "@/icons";

export const AddButton = (props: ButtonProps) => {
const { sx, ...rest } = props;

return (
<Button
color="primary"
variant="contained"
startIcon={<Icon name="add" />}
sx={{
width: "fit-content",
ml: "0.5rem",
px: 3,
...sx,
}}
{...rest}
/>
);
};
35 changes: 15 additions & 20 deletions app/components/chart-panel-layout-grid.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import clsx from "clsx";
import { fold } from "fp-ts/lib/Either";
import { pipe } from "fp-ts/lib/function";
import { useState } from "react";
import { Layouts } from "react-grid-layout";

import { ChartPanelLayoutTypeProps } from "@/components/chart-panel";
Expand Down Expand Up @@ -33,26 +32,25 @@ const decodeLayouts = (layouts: Layouts) => {
);
};

const ChartPanelLayoutCanvas = (props: ChartPanelLayoutTypeProps) => {
const { chartConfigs } = props;
export const ChartPanelLayoutCanvas = ({
blocks,
renderBlock,
className,
}: ChartPanelLayoutTypeProps) => {
const [state, dispatch] = useConfiguratorState(hasChartConfigs);
const [layouts, setLayouts] = useState<Layouts>(() => {
assert(
state.layout.type === "dashboard" && state.layout.layout === "canvas",
"ChartPanelLayoutGrid should be rendered only for dashboard layout with canvas"
);

return state.layout.layouts;
});

const layout = state.layout;
assert(
layout.type === "dashboard" && layout.layout === "canvas",
"ChartPanelLayoutGrid should be rendered only for dashboard layout with canvas"
);
const handleChangeLayouts = (layouts: Layouts) => {
const layout = state.layout;
assert(
layout.type === "dashboard" && layout.layout === "canvas",
"ChartPanelLayoutGrid should be rendered only for dashboard layout with canvas"
);

const parsedLayouts = decodeLayouts(layouts);

if (!parsedLayouts) {
return;
}
Expand All @@ -64,22 +62,19 @@ const ChartPanelLayoutCanvas = (props: ChartPanelLayoutTypeProps) => {
layouts: parsedLayouts,
},
});
setLayouts(layouts);
};

return (
<ChartGridLayout
key={state.state}
className={clsx(chartPanelLayoutGridClasses.root, props.className)}
layouts={layouts}
className={clsx(chartPanelLayoutGridClasses.root, className)}
layouts={layout.layouts}
resize={state.state === "LAYOUTING"}
draggableHandle={`.${chartPanelLayoutGridClasses.dragHandle}`}
onLayoutChange={(_l, allLayouts) => handleChangeLayouts(allLayouts)}
onLayoutChange={(_, allLayouts) => handleChangeLayouts(allLayouts)}
breakpoints={FREE_CANVAS_BREAKPOINTS}
>
{chartConfigs.map((chartConfig) => props.renderChart(chartConfig))}
{blocks.map(renderBlock)}
</ChartGridLayout>
);
};

export default ChartPanelLayoutCanvas;
62 changes: 26 additions & 36 deletions app/components/chart-panel-layout-tall.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { Box, useMediaQuery } from "@mui/material";
import { useMemo } from "react";

import { ChartPanelLayoutTypeProps } from "@/components/chart-panel";
import classes from "@/components/chart-panel-layout-tall.module.css";
import { ChartConfig } from "@/config-types";
import { LayoutBlock } from "@/config-types";
import { useTheme } from "@/themes";

type ChartPanelLayoutTallProps = {
chartConfigs: ChartConfig[];
renderChart: (chartConfig: ChartConfig) => JSX.Element;
};

export const ChartPanelLayoutTall = (props: ChartPanelLayoutTallProps) => {
const { chartConfigs, renderChart } = props;
export const ChartPanelLayoutTall = ({
blocks,
renderBlock,
}: ChartPanelLayoutTypeProps) => {
const rows = useMemo(() => {
return getChartPanelLayoutTallRows(chartConfigs, renderChart);
}, [chartConfigs, renderChart]);
return getChartPanelLayoutTallRows({ blocks, renderBlock });
}, [blocks, renderBlock]);

return (
<>
Expand All @@ -24,67 +22,59 @@ export const ChartPanelLayoutTall = (props: ChartPanelLayoutTallProps) => {
</>
);
};
type ChartPanelLayoutTallRowProps = {
row: ChartPanelLayoutTallRow;
};

const ChartPanelLayoutTallRow = (props: ChartPanelLayoutTallRowProps) => {
const { row } = props;
const ChartPanelLayoutTallRow = ({ row }: { row: ChartPanelLayoutTallRow }) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("md"));

switch (row.type) {
case "wide":
return row.renderChart(row.chartConfig);
return row.renderBlock(row.block);
case "narrow":
if (isMobile) {
return <>{row.chartConfigs.map(row.renderChart)}</>;
return <>{row.blocks.map(row.renderBlock)}</>;
}

return (
<Box className={classes.root}>
{row.chartConfigs.map(row.renderChart)}
</Box>
<Box className={classes.root}>{row.blocks.map(row.renderBlock)}</Box>
);
}
};
type ChartPanelLayoutTallRow = {
renderChart: (chartConfig: ChartConfig) => JSX.Element;
renderBlock: (block: LayoutBlock) => JSX.Element;
} & (
| {
type: "wide";
chartConfig: ChartConfig;
block: LayoutBlock;
}
| {
type: "narrow";
chartConfigs: [ChartConfig] | [ChartConfig, ChartConfig];
blocks: [LayoutBlock] | [LayoutBlock, LayoutBlock];
}
);

const getChartPanelLayoutTallRows = (
chartConfigs: ChartConfig[],
renderChart: (chartConfig: ChartConfig) => JSX.Element
): ChartPanelLayoutTallRow[] => {
const getChartPanelLayoutTallRows = ({
blocks,
renderBlock,
}: ChartPanelLayoutTypeProps): ChartPanelLayoutTallRow[] => {
const rows: ChartPanelLayoutTallRow[] = [];

for (let i = 0; i < chartConfigs.length; i += 1) {
for (let i = 0; i < blocks.length; i += 1) {
if (i % 3 === 0) {
rows.push({
type: "wide",
chartConfig: chartConfigs[i],
renderChart,
block: blocks[i],
renderBlock,
});
}

if (i % 3 === 1) {
const currentConfig = chartConfigs[i];
const nextConfig = chartConfigs[i + 1];
const block = blocks[i];
const nextBlock = blocks[i + 1];
rows.push({
type: "narrow",
chartConfigs: nextConfig
? [currentConfig, nextConfig]
: [currentConfig],
renderChart,
blocks: nextBlock ? [block, nextBlock] : [block],
renderBlock,
});
}
}
Expand Down
8 changes: 5 additions & 3 deletions app/components/chart-panel-layout-vertical.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ChartPanelLayoutTypeProps } from "@/components/chart-panel";

export const ChartPanelLayoutVertical = (props: ChartPanelLayoutTypeProps) => {
const { chartConfigs, renderChart } = props;
return <>{chartConfigs.map(renderChart)}</>;
export const ChartPanelLayoutVertical = ({
blocks,
renderBlock,
}: ChartPanelLayoutTypeProps) => {
return <>{blocks.map(renderBlock)}</>;
};
Loading
Loading