Skip to content

Commit

Permalink
Seperate out link logic to improve dashboard loading
Browse files Browse the repository at this point in the history
  • Loading branch information
Heenawter committed Jul 10, 2023
1 parent ca0ba08 commit 2ddb6ec
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 209 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,6 @@ export const fetchDashboard = async (dashboardId: string): Promise<DashboardItem
return response;
};

/**
* Memoized fetch dashboard will only refetch the dashboard information if the given `dashboardId` changed between
* calls; otherwise, it will use the cached dashboard, which may not take into account changes to the dashboard's title
* description, etc. Be mindful when choosing the memoized version.
*/
export const memoizedFetchDashboard = memoize(
async (dashboardId: string) => {
return await fetchDashboard(dashboardId);
},
(dashboardId) => {
return dashboardId;
}
);

/**
* ----------------------------------
* Fetch lists of dashboards
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,15 @@ export const NavigationEmbeddableLinkEditor = ({
onClick={() => {
// this check should always be true, since the button is disabled otherwise - this is just for type safety
if (linkDestination) {
const linkId = idToEdit && linkToEdit ? idToEdit : uuidv4();
onSave({
...links,
[idToEdit && linkToEdit ? idToEdit : uuidv4()]: {
destination: linkDestination,
label: linkLabel,
[linkId]: {
order: 0,
id: linkId,
label: linkLabel,
type: selectedLinkType,
destination: linkDestination,
},
});

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,31 @@
*/

import { isEmpty, omit } from 'lodash';
import useAsync from 'react-use/lib/useAsync';
import React, { useCallback, useMemo, useState } from 'react';

import {
EuiText,
EuiIcon,
EuiForm,
EuiTitle,
EuiPanel,
IconType,
EuiSpacer,
EuiButton,
EuiFormRow,
EuiFlexItem,
EuiFlexGroup,
EuiFlyoutBody,
EuiButtonIcon,
EuiButtonEmpty,
EuiFlyoutFooter,
EuiFlyoutHeader,
} from '@elastic/eui';
import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container';

import {
NavigationLinkInfo,
EXTERNAL_LINK_TYPE,
DASHBOARD_LINK_TYPE,
NavigationEmbeddableInput,
NavigationEmbeddableLinkList,
} from '../embeddable/types';
import { NavEmbeddableStrings } from './navigation_embeddable_strings';
import { memoizedFetchDashboard } from './dashboard_link/dashboard_link_tools';
import { openLinkEditorFlyout } from '../editor/open_link_editor_flyout';
import { NavigationEmbeddableInput, NavigationEmbeddableLinkList } from '../embeddable/types';
import { NavigationEmbeddablePanelEditorLink } from './navigation_embeddable_panel_editor_link';

import './navigation_embeddable.scss';
import { openLinkEditorFlyout } from '../editor/open_link_editor_flyout';

export const NavigationEmbeddablePanelEditor = ({
onSave,
Expand All @@ -55,16 +45,15 @@ export const NavigationEmbeddablePanelEditor = ({
parentDashboard?: DashboardContainer;
}) => {
const editLinkFlyoutRef: React.RefObject<HTMLDivElement> = useMemo(() => React.createRef(), []);

const [links, setLinks] = useState<NavigationEmbeddableLinkList>(initialInput?.links ?? {});

const addOrEditLink = useCallback(
async (linkToEditId?: string) => {
const newLinks = await openLinkEditorFlyout({
links,
parentDashboard,
idToEdit: linkToEditId, // if this is defined, then we are editing; otherwise, we are adding
ref: editLinkFlyoutRef,
idToEdit: linkToEditId, // if this is defined, then we are editing; otherwise, we are adding
});
if (newLinks) setLinks(newLinks);
},
Expand All @@ -75,38 +64,9 @@ export const NavigationEmbeddablePanelEditor = ({
(linkId: string) => {
setLinks(omit(links, [linkId]));
},
[links]
[links, setLinks]
);

/**
* TODO: There is probably a more efficient way of storing the dashboard information "temporarily" for any new
* panels and only fetching the dashboard saved objects when first loading this flyout.
*
* Will need to think this through and fix as part of the editing process - not worth holding this PR, since it's
* blocking so much other work :)
*/
const { value: linkList } = useAsync(async () => {
if (!links || isEmpty(links)) return [];

const newLinks: Array<{ id: string; icon: IconType; label: string }> = await Promise.all(
Object.keys(links).map(async (panelId) => {
let label = links[panelId].label;
let icon = NavigationLinkInfo[EXTERNAL_LINK_TYPE].icon;

if (links[panelId].type === DASHBOARD_LINK_TYPE) {
icon = NavigationLinkInfo[DASHBOARD_LINK_TYPE].icon;
if (!label) {
const dashboard = await memoizedFetchDashboard(links[panelId].destination);
label = dashboard.attributes.title;
}
}

return { id: panelId, label: label || links[panelId].destination, icon };
})
);
return newLinks;
}, [links]);

return (
<>
<div ref={editLinkFlyoutRef} />
Expand Down Expand Up @@ -139,57 +99,14 @@ export const NavigationEmbeddablePanelEditor = ({
</EuiPanel>
) : (
<>
{linkList?.map((link) => {
{Object.keys(links).map((linkId) => {
return (
<div key={link.id}>
<EuiPanel
className="navEmbeddablePanelEditor"
hasBorder
hasShadow={false}
paddingSize="s"
>
<EuiFlexGroup
gutterSize="s"
responsive={false}
wrap={false}
alignItems="center"
>
<EuiFlexItem grow={false}>
<EuiIcon type={link.icon} color="text" />
</EuiFlexItem>
<EuiFlexItem className="linkText">
<div className="wrapText">{link.label}</div>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup
gutterSize="none"
className="navEmbeddable_hoverActions"
>
<EuiFlexItem>
<EuiButtonIcon
size="xs"
iconType="pencil"
aria-label="Edit"
onClick={() => {
addOrEditLink(link.id);
}}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiButtonIcon
size="xs"
iconType="trash"
aria-label="Delete"
color="danger"
onClick={() => {
deleteLink(link.id);
}}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
<div key={linkId}>
<NavigationEmbeddablePanelEditorLink
editLink={() => addOrEditLink(linkId)}
link={links[linkId]}
deleteLink={() => deleteLink(linkId)}
/>
<EuiSpacer size="s" />
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import React from 'react';
import useAsync from 'react-use/lib/useAsync';

import {
EuiIcon,
EuiPanel,
EuiFlexItem,
EuiFlexGroup,
EuiButtonIcon,
EuiSkeletonTitle,
} from '@elastic/eui';

import {
NavigationLinkInfo,
DASHBOARD_LINK_TYPE,
NavigationEmbeddableLink,
} from '../embeddable/types';
import { fetchDashboard } from './dashboard_link/dashboard_link_tools';

export const NavigationEmbeddablePanelEditorLink = ({
link,
editLink,
deleteLink,
}: {
editLink: () => void;
deleteLink: () => void;
link: NavigationEmbeddableLink;
}) => {
const { value: linkLabel, loading: linkLabelLoading } = useAsync(async () => {
let label = link.label;
if (link.type === DASHBOARD_LINK_TYPE && !label) {
const dashboard = await fetchDashboard(link.destination);
label = dashboard.attributes.title;
}
return label || link.destination;
}, [link]);

return (
<EuiPanel hasBorder paddingSize="s" hasShadow={false} className="navEmbeddablePanelEditor">
<EuiFlexGroup gutterSize="s" responsive={false} wrap={false} alignItems="center">
<EuiFlexItem grow={false}>
<EuiIcon type={NavigationLinkInfo[link.type].icon} color="text" />
</EuiFlexItem>
<EuiFlexItem className="linkText">
<EuiSkeletonTitle
size="xxxs"
isLoading={linkLabelLoading}
contentAriaLabel="Demo skeleton title"
>
<div className="wrapText">{linkLabel}</div>
</EuiSkeletonTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="none" className="navEmbeddable_hoverActions">
<EuiFlexItem>
<EuiButtonIcon size="xs" iconType="pencil" aria-label="Edit" onClick={editLink} />
</EuiFlexItem>
<EuiFlexItem>
<EuiButtonIcon
size="xs"
iconType="trash"
aria-label="Delete"
color="danger"
onClick={deleteLink}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const EXTERNAL_LINK_TYPE = 'externalLink';
export type NavigationLinkType = typeof DASHBOARD_LINK_TYPE | typeof EXTERNAL_LINK_TYPE;

export interface NavigationEmbeddableLink {
id: string;
type: NavigationLinkType;
destination: string;
label?: string;
Expand Down

0 comments on commit 2ddb6ec

Please sign in to comment.