Skip to content

Commit

Permalink
Working on editing dashboard links
Browse files Browse the repository at this point in the history
  • Loading branch information
Heenawter committed Jul 10, 2023
1 parent 69564b2 commit 98e05fb
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ import { DashboardLinkEmbeddableStrings } from './dashboard_link_strings';
export const DashboardLinkDestinationPicker = ({
setDestination,
setPlaceholder,
currentDestination,
parentDashboard,
initialSelection,
...other
}: {
setDestination: (destination?: string) => void;
setPlaceholder: (placeholder?: string) => void;
currentDestination?: string;
parentDashboard?: DashboardContainer;
initialSelection?: string;
}) => {
const [searchString, setSearchString] = useState<string>('');
const [selectedDashboard, setSelectedDashboard] = useState<DashboardItem | undefined>();
Expand All @@ -43,7 +43,11 @@ export const DashboardLinkDestinationPicker = ({
const parentDashboardId = parentDashboard?.select((state) => state.componentState.lastSavedId);

const { loading: loadingDashboardList, value: dashboardList } = useAsync(async () => {
return await memoizedFetchDashboards(searchString, undefined, parentDashboardId);
return await memoizedFetchDashboards({
search: searchString,
currentDashboardId: parentDashboardId,
selectedDashboardId: initialSelection,
});
}, [searchString, parentDashboardId]);

useEffect(() => {
Expand All @@ -52,6 +56,7 @@ export const DashboardLinkDestinationPicker = ({
return {
data: dashboard,
label: dashboard.attributes.title,
checked: initialSelection && dashboard.id === initialSelection ? 'on' : undefined,
...(dashboard.id === parentDashboardId
? {
prepend: (
Expand All @@ -63,7 +68,7 @@ export const DashboardLinkDestinationPicker = ({
}) ?? [];

setDashboardListOptions(dashboardOptions);
}, [dashboardList, parentDashboardId, searchString]);
}, [dashboardList, parentDashboardId, initialSelection, searchString]);

const debouncedSetSearch = useMemo(
() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,16 @@
* Side Public License, v 1.
*/

import { isEmpty, memoize } from 'lodash';
import { isEmpty, memoize, filter } from 'lodash';
import { DashboardItem } from '../../embeddable/types';

import { dashboardServices } from '../../services/kibana_services';

/**
* 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.
* ----------------------------------
* Fetch a single dashboard
* ----------------------------------
*/
export const memoizedFetchDashboard = memoize(
async (dashboardId: string) => {
return await fetchDashboard(dashboardId);
},
(dashboardId) => {
return dashboardId;
}
);

export const fetchDashboard = async (dashboardId: string): Promise<DashboardItem> => {
const findDashboardsService = await dashboardServices.findDashboardsService();
Expand All @@ -34,49 +26,64 @@ export const fetchDashboard = async (dashboardId: string): Promise<DashboardItem
return response;
};

export const memoizedFetchDashboards = memoize(
async (search: string = '', size: number = 10, currentDashboardId?: string) => {
return await fetchDashboards(search, size, currentDashboardId);
/**
* 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);
},
(search, size, currentDashboardId) => {
return [search, size, currentDashboardId].join('|');
(dashboardId) => {
return dashboardId;
}
);

const fetchDashboards = async (
search: string = '',
size: number = 10,
currentDashboardId?: string
): Promise<DashboardItem[]> => {
/**
* ----------------------------------
* Fetch lists of dashboards
* ----------------------------------
*/

interface FetchDashboardsProps {
size?: number;
search?: string;
currentDashboardId?: string;
selectedDashboardId?: string;
}

const fetchDashboards = async ({
search = '',
size = 10,
currentDashboardId,
selectedDashboardId,
}: FetchDashboardsProps): Promise<DashboardItem[]> => {
const findDashboardsService = await dashboardServices.findDashboardsService();
const responses = await findDashboardsService.search({
search,
size,
options: { onlyTitle: true },
});

let currentDashboard: DashboardItem | undefined;
let dashboardList: DashboardItem[] = responses.hits;

/** When the parent dashboard has been saved (i.e. it has an ID) and there is no search string ... */
if (currentDashboardId && isEmpty(search)) {
/** ...force the current dashboard (if it is present in the original search results) to the top of the list */
dashboardList = dashboardList.sort((dashboard) => {
const isCurrentDashboard = dashboard.id === currentDashboardId;
if (isCurrentDashboard) {
currentDashboard = dashboard;
}
return isCurrentDashboard ? -1 : 1;
/** If there is no search string... */
if (isEmpty(search)) {
/** ... filter out both the current and parent dashboard from the list ... */
dashboardList = filter(dashboardList, (dash) => {
return dash.id !== currentDashboardId && dash.id !== selectedDashboardId;
});

/**
* If the current dashboard wasn't returned in the original search, perform another search to find it and
* force it to the front of the list
*/
if (!currentDashboard) {
currentDashboard = await fetchDashboard(currentDashboardId);
/** ... so that we can force them to the top of the list as necessary. */
if (currentDashboardId) {
dashboardList.pop(); // the result should still be of `size,` so remove the dashboard at the end of the list
dashboardList.unshift(currentDashboard); // in order to force the current dashboard to the start of the list
dashboardList.unshift(await fetchDashboard(currentDashboardId)); // in order to force the current dashboard to the start of the list
}

if (selectedDashboardId !== currentDashboardId && selectedDashboardId) {
dashboardList.pop();
dashboardList.unshift(await fetchDashboard(selectedDashboardId));
}
}

Expand All @@ -87,3 +94,17 @@ const fetchDashboards = async (

return simplifiedDashboardList;
};

export const memoizedFetchDashboards = memoize(
async ({ search, size, currentDashboardId, selectedDashboardId }: FetchDashboardsProps) => {
return await fetchDashboards({
search,
size,
currentDashboardId,
selectedDashboardId,
});
},
({ search, size, currentDashboardId, selectedDashboardId }) => {
return [search, size, currentDashboardId, selectedDashboardId].join('|');
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ const isValidUrl =
export const ExternalLinkDestinationPicker = ({
setDestination,
setPlaceholder,
currentDestination,
initialSelection,
...other
}: {
setDestination: (destination?: string) => void;
setPlaceholder: (placeholder?: string) => void;
currentDestination?: string;
initialSelection?: string;
}) => {
const [validUrl, setValidUrl] = useState<boolean>(true);
const [urlValue, setUrlValue] = useState(currentDestination);
const [urlValue, setUrlValue] = useState(initialSelection);

useMount(() => {
if (urlValue && urlValue.length > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,10 @@ export const NavigationEmbeddableLinkEditor = ({
const [selectedLinkType, setSelectedLinkType] = useState<NavigationLinkType>(
linkToEdit.current ? linkToEdit.current.type : DASHBOARD_LINK_TYPE
);
const [linkLabel, setLinkLabel] = useState<string>(
linkToEdit.current ? linkToEdit.current.label || '' : ''
);
const [linkDestination, setLinkDestination] = useState<string | undefined>(
linkToEdit.current?.destination
);
const [linkLabel, setLinkLabel] = useState<string>();
const [linkDestination, setLinkDestination] = useState<string | undefined>();
const [linkLabelPlaceholder, setLinkLabelPlaceholder] = useState<string | undefined>();

console.log(linkToEdit.current);

const linkTypes: EuiRadioGroupOption[] = useMemo(() => {
return ([DASHBOARD_LINK_TYPE, EXTERNAL_LINK_TYPE] as NavigationLinkType[]).map((type) => {
return {
Expand Down Expand Up @@ -114,8 +108,12 @@ export const NavigationEmbeddableLinkEditor = ({
options={linkTypes}
idSelected={selectedLinkType}
onChange={(id) => {
setLinkDestination(undefined);
setLinkLabelPlaceholder(undefined);
if (linkToEdit.current?.type === id) {
setLinkDestination(linkToEdit.current.destination);
} else {
setLinkDestination(undefined);
setLinkLabelPlaceholder(undefined);
}
setSelectedLinkType(id as NavigationLinkType);
}}
/>
Expand All @@ -126,13 +124,13 @@ export const NavigationEmbeddableLinkEditor = ({
<DashboardLinkDestinationPicker
parentDashboard={parentDashboard}
setDestination={setLinkDestination}
currentDestination={linkDestination}
initialSelection={linkToEdit.current?.destination}
setPlaceholder={setLinkLabelPlaceholder}
/>
) : (
<ExternalLinkDestinationPicker
setDestination={setLinkDestination}
currentDestination={linkDestination}
initialSelection={linkToEdit.current?.destination}
setPlaceholder={setLinkLabelPlaceholder}
/>
)}
Expand All @@ -144,7 +142,7 @@ export const NavigationEmbeddableLinkEditor = ({
linkLabelPlaceholder ||
NavEmbeddableStrings.editor.linkEditor.getLinkTextPlaceholder()
}
value={linkLabel}
value={linkLabel || linkToEdit.current?.label}
onChange={(e) => {
setLinkLabel(e.target.value);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import {
EuiFlexItem,
EuiFlexGroup,
EuiFlyoutBody,
EuiButtonIcon,
EuiButtonEmpty,
EuiFlyoutFooter,
EuiFlyoutHeader,
EuiButtonIcon,
} from '@elastic/eui';
import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container';

Expand Down Expand Up @@ -63,11 +63,10 @@ export const NavigationEmbeddablePanelEditor = ({
const newLinks = await openLinkEditorFlyout({
links,
parentDashboard,
idToEdit: linkToEditId,
idToEdit: linkToEditId, // if this is defined, then we are editing; otherwise, we are adding
ref: editLinkFlyoutRef,
});
console.log('new links', newLinks);
setLinks(newLinks);
if (newLinks) setLinks(newLinks);
},
[editLinkFlyoutRef, links, parentDashboard]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ export async function openLinkEditorFlyout({
links,
idToEdit,
parentDashboard,
}: LinkEditorProps): Promise<NavigationEmbeddableLinkList> {
return new Promise((resolve, reject) => {
}: LinkEditorProps): Promise<NavigationEmbeddableLinkList | undefined> {
return new Promise<NavigationEmbeddableLinkList | undefined>((resolve, reject) => {
const onSave = (newLinks: NavigationEmbeddableLinkList) => {
console.log('on save', newLinks);
// console.log('on save', newLinks);
resolve(newLinks);
if (ref.current) ReactDOM.unmountComponentAtNode(ref.current);
};
Expand All @@ -56,5 +56,8 @@ export async function openLinkEditorFlyout({
</KibanaThemeProvider>,
ref.current
);
}).catch(() => {
// on reject (i.e. on cancel), just return the original list of links
return undefined;
});
}

0 comments on commit 98e05fb

Please sign in to comment.