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: card section and dashboards section UX improvements #7693

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@
}

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 @@
);
});

// 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 { 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 @@
hidePanelTitles: true,
viewMode: ViewMode.VIEW,
columns: section.columns,
wrap: section.wrap,
panels,
...section.input,
};
Expand Down Expand Up @@ -71,12 +74,26 @@
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 @@
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 @@
},
};

// 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
Loading