Skip to content

Commit

Permalink
feat: card section and dashboards section UX improvements (#7693)
Browse files Browse the repository at this point in the history
Signed-off-by: Yulong Ruan <[email protected]>
(cherry picked from commit a258bd6)
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
github-actions[bot] committed Aug 21, 2024
1 parent 3835fc2 commit c9e9b67
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@ interface Props {
}

const CardListInner = ({ embeddable, input, embeddableServices }: Props) => {
if (input.columns) {
const width = `${(1 / input.columns) * 100}%`;
const cards = Object.values(input.panels).map((panel) => {
const child = embeddable.getChild(panel.explicitInput.id);
return (

Check warning on line 29 in src/plugins/content_management/public/components/card_container/card_list.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/content_management/public/components/card_container/card_list.tsx#L26-L29

Added lines #L26 - L29 were not covered by tests
<EuiFlexItem key={panel.explicitInput.id} style={{ minWidth: `calc(${width} - 8px)` }}>
<embeddableServices.EmbeddablePanel embeddable={child} />
</EuiFlexItem>
);
});
return (

Check warning on line 35 in src/plugins/content_management/public/components/card_container/card_list.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/content_management/public/components/card_container/card_list.tsx#L35

Added line #L35 was not covered by tests
<EuiFlexGroup
wrap={!!input.wrap}
style={input.wrap ? {} : { overflowX: 'auto' }}
gutterSize="s"
>
{cards}
</EuiFlexGroup>
);
}

const cards = Object.values(input.panels).map((panel) => {
const child = embeddable.getChild(panel.explicitInput.id);
return (
Expand All @@ -31,10 +52,9 @@ const CardListInner = ({ embeddable, input, embeddableServices }: Props) => {
);
});

// TODO: we should perhaps display the cards in multiple rows when the actual number of cards exceed the column size
return (
<EuiFlexGroup gutterSize="s">
{input.columns ? cards.slice(0, input.columns) : cards}
<EuiFlexGroup wrap={input.wrap} gutterSize="s">
{cards}
</EuiFlexGroup>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ export interface CardExplicitInput {
getFooter?: () => React.ReactElement;
}

export type CardContainerInput = ContainerInput<CardExplicitInput> & { columns?: number };
export type CardContainerInput = ContainerInput<CardExplicitInput> & {
columns?: number;
wrap?: boolean;
};

/**
* The props which allow to be updated after card container was created
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { coreMock } from '../../../../core/public/mocks';
import { Content, Section } from '../services';
import { createCardInput, createDashboardInput } from './section_input';
import { DASHBOARD_PANEL_WIDTH, createCardInput, createDashboardInput } from './section_input';

test('it should create card section input', () => {
const section: Section = { id: 'section1', kind: 'card', order: 10 };
Expand Down Expand Up @@ -363,3 +363,119 @@ test('it should create section with a dynamic dashboard as content', async () =>
},
});
});

test('it renders content with custom width and height', async () => {
const customWidth = 24;
const customHeight = 20;
const section: Section = { id: 'section1', kind: 'dashboard', order: 10 };
const staticViz: Content = {
id: 'content1',
kind: 'visualization',
order: 0,
width: customWidth,
height: customHeight,
input: {
kind: 'static',
id: 'viz-id-static',
},
};

const clientMock = coreMock.createStart().savedObjects.client;
const input = await createDashboardInput(section, [staticViz], {
savedObjectsClient: clientMock,
});

expect(input.panels).toEqual({
content1: {
explicitInput: {
disabledActions: ['togglePanel'],
id: 'content1',
savedObjectId: 'viz-id-static',
},
gridData: {
i: 'content1',
h: customHeight,
w: customWidth,
x: 0,
y: 0,
},
type: 'visualization',
},
});
});

test('it uses default width if custom content width is <= 0', async () => {
const customWidthShouldBeBiggerThan0 = 0;
const section: Section = { id: 'section1', kind: 'dashboard', order: 10 };
const staticViz: Content = {
id: 'content1',
kind: 'visualization',
order: 0,
width: customWidthShouldBeBiggerThan0,
input: {
kind: 'static',
id: 'viz-id-static',
},
};

const clientMock = coreMock.createStart().savedObjects.client;
const input = await createDashboardInput(section, [staticViz], {
savedObjectsClient: clientMock,
});

expect(input.panels).toEqual({
content1: {
explicitInput: {
disabledActions: ['togglePanel'],
id: 'content1',
savedObjectId: 'viz-id-static',
},
gridData: {
h: 15,
i: 'content1',
w: DASHBOARD_PANEL_WIDTH,
x: 0,
y: 0,
},
type: 'visualization',
},
});
});

test('it should use default width if custom content width > DASHBOARD_GRID_COLUMN_COUNT: 48', async () => {
const customWidthShouldNotBeBiggerThan0 = 49;
const section: Section = { id: 'section1', kind: 'dashboard', order: 10 };
const staticViz: Content = {
id: 'content1',
kind: 'visualization',
order: 0,
width: customWidthShouldNotBeBiggerThan0,
input: {
kind: 'static',
id: 'viz-id-static',
},
};

const clientMock = coreMock.createStart().savedObjects.client;
const input = await createDashboardInput(section, [staticViz], {
savedObjectsClient: clientMock,
});

expect(input.panels).toEqual({
content1: {
explicitInput: {
disabledActions: ['togglePanel'],
id: 'content1',
savedObjectId: 'viz-id-static',
},
gridData: {
h: 15,
i: 'content1',
w: DASHBOARD_PANEL_WIDTH,
x: 0,
y: 0,
},
type: 'visualization',
},
});
});
46 changes: 33 additions & 13 deletions src/plugins/content_management/public/components/section_input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { CARD_EMBEDDABLE } from './card_container/card_embeddable';
import { CardContainerInput } from './card_container/types';

const DASHBOARD_GRID_COLUMN_COUNT = 48;
export const DASHBOARD_PANEL_WIDTH = 12;
export const DASHBOARD_PANEL_HEIGHT = 15;

export const createCardInput = (
section: Section,
Expand All @@ -31,6 +33,7 @@ export const createCardInput = (
hidePanelTitles: true,
viewMode: ViewMode.VIEW,
columns: section.columns,
wrap: section.wrap,
panels,
...section.input,
};
Expand Down Expand Up @@ -71,12 +74,26 @@ export const createDashboardInput = async (
const panels: DashboardContainerInput['panels'] = {};
let x = 0;
let y = 0;
const w = 12;
const h = 15;
const counter = new BehaviorSubject(0);

contents.forEach(async (content) => {
counter.next(counter.value + 1);

let w = DASHBOARD_PANEL_WIDTH;
let h = DASHBOARD_PANEL_HEIGHT;

if ('width' in content && typeof content.width === 'number') {
if (content.width > 0 && content.width <= DASHBOARD_GRID_COLUMN_COUNT) {
w = content.width;
}
}

if ('height' in content && typeof content.height === 'number') {
if (content.height > 0) {
h = content.height;
}
}

try {
if (content.kind === 'dashboard') {
let dashboardId = '';
Expand Down Expand Up @@ -120,7 +137,13 @@ export const createDashboardInput = async (
return;
}

const config: DashboardContainerInput['panels'][string] = {
// If current panel exceed the max dashboard container width, add the panel to the next row
if (x + w > DASHBOARD_GRID_COLUMN_COUNT) {
x = 0;
y = y + h;

Check warning on line 143 in src/plugins/content_management/public/components/section_input.ts

View check run for this annotation

Codecov / codecov/patch

src/plugins/content_management/public/components/section_input.ts#L142-L143

Added lines #L142 - L143 were not covered by tests
}

const panelConfig: DashboardContainerInput['panels'][string] = {
gridData: {
w,
h,
Expand All @@ -135,28 +158,25 @@ export const createDashboardInput = async (
},
};

// The new x starts from the current panel x + current panel width
x = x + w;
if (x >= DASHBOARD_GRID_COLUMN_COUNT) {
x = 0;
y = y + h;
}

if (content.kind === 'visualization') {
config.type = 'visualization';
panelConfig.type = 'visualization';
if (content.input.kind === 'dynamic') {
config.explicitInput.savedObjectId = await content.input.get();
panelConfig.explicitInput.savedObjectId = await content.input.get();
}
if (content.input.kind === 'static') {
config.explicitInput.savedObjectId = content.input.id;
panelConfig.explicitInput.savedObjectId = content.input.id;
}
}

if (content.kind === 'custom') {
config.type = CUSTOM_CONTENT_EMBEDDABLE;
config.explicitInput.render = content.render;
panelConfig.type = CUSTOM_CONTENT_EMBEDDABLE;
panelConfig.explicitInput.render = content.render;
}

panels[content.id] = config;
panels[content.id] = panelConfig;
} catch (e) {
// eslint-disable-next-line
console.log(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ export type Section =
id: string;
order: number;
title?: string;
columns?: number;
input?: CardContainerExplicitInput;
columns?: number;
wrap?: boolean;
};

export type Content =
Expand All @@ -45,18 +46,24 @@ export type Content =
id: string;
order: number;
input: SavedObjectInput;
width?: number;
height?: number;
}
| {
kind: 'dashboard';
id: string;
order: number;
input: SavedObjectInput;
width?: number;
height?: number;
}
| {
kind: 'custom';
id: string;
order: number;
render: () => JSX.Element;
width?: number;
height?: number;
}
| {
kind: 'card';
Expand Down

0 comments on commit c9e9b67

Please sign in to comment.