Dashboard: Chore - Remove rudderstack events from panel menu and toolbar (#91376)

* Chore: Remove rudderstack events from panel interactions, and toolbar in dashboards

- dashboards_panelheader_menu
- dashboards_panelheader_description_displayed
- dashboards_toolbar_actions_clicked

* Add back some toolbar events: sharing, settings, favourites, and add

* restore ShareButton
This commit is contained in:
Alexa V 2024-08-02 13:30:47 +02:00 committed by GitHub
parent 44ed331239
commit 0145b0fe70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 16 additions and 115 deletions

View File

@ -496,7 +496,6 @@ export function ToolbarActions({ dashboard }: Props) {
return ( return (
<Button <Button
onClick={() => { onClick={() => {
DashboardInteractions.toolbarSaveClick();
dashboard.openSaveDrawer({}); dashboard.openSaveDrawer({});
}} }}
className={styles.buttonWithExtraMargin} className={styles.buttonWithExtraMargin}
@ -516,7 +515,6 @@ export function ToolbarActions({ dashboard }: Props) {
return ( return (
<Button <Button
onClick={() => { onClick={() => {
DashboardInteractions.toolbarSaveClick();
dashboard.openSaveDrawer({ saveAsCopy: true }); dashboard.openSaveDrawer({ saveAsCopy: true });
}} }}
className={styles.buttonWithExtraMargin} className={styles.buttonWithExtraMargin}
@ -537,7 +535,6 @@ export function ToolbarActions({ dashboard }: Props) {
label="Save" label="Save"
icon="save" icon="save"
onClick={() => { onClick={() => {
DashboardInteractions.toolbarSaveClick();
dashboard.openSaveDrawer({}); dashboard.openSaveDrawer({});
}} }}
/> />
@ -545,7 +542,6 @@ export function ToolbarActions({ dashboard }: Props) {
label="Save as copy" label="Save as copy"
icon="copy" icon="copy"
onClick={() => { onClick={() => {
DashboardInteractions.toolbarSaveAsClick();
dashboard.openSaveDrawer({ saveAsCopy: true }); dashboard.openSaveDrawer({ saveAsCopy: true });
}} }}
/> />
@ -556,7 +552,6 @@ export function ToolbarActions({ dashboard }: Props) {
<ButtonGroup className={styles.buttonWithExtraMargin} key="save"> <ButtonGroup className={styles.buttonWithExtraMargin} key="save">
<Button <Button
onClick={() => { onClick={() => {
DashboardInteractions.toolbarSaveClick();
dashboard.openSaveDrawer({}); dashboard.openSaveDrawer({});
}} }}
tooltip="Save changes" tooltip="Save changes"

View File

@ -64,7 +64,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
text: t('panel.header-menu.view', `View`), text: t('panel.header-menu.view', `View`),
iconClassName: 'eye', iconClassName: 'eye',
shortcut: 'v', shortcut: 'v',
onClick: () => DashboardInteractions.panelMenuItemClicked('view'),
href: getViewPanelUrl(panel), href: getViewPanelUrl(panel),
}); });
} }
@ -76,7 +75,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
text: t('panel.header-menu.edit', `Edit`), text: t('panel.header-menu.edit', `Edit`),
iconClassName: 'edit', iconClassName: 'edit',
shortcut: 'e', shortcut: 'e',
onClick: () => DashboardInteractions.panelMenuItemClicked('edit'),
href: getEditPanelUrl(getPanelIdForVizPanel(panel)), href: getEditPanelUrl(getPanelIdForVizPanel(panel)),
}); });
} }
@ -111,7 +109,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
text: t('panel.header-menu.share', 'Share'), text: t('panel.header-menu.share', 'Share'),
iconClassName: 'share-alt', iconClassName: 'share-alt',
onClick: () => { onClick: () => {
DashboardInteractions.panelMenuItemClicked('share');
dashboard.showModal(new ShareModal({ panelRef: panel.getRef() })); dashboard.showModal(new ShareModal({ panelRef: panel.getRef() }));
}, },
shortcut: 'p s', shortcut: 'p s',
@ -122,7 +119,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
moreSubMenu.push({ moreSubMenu.push({
text: t('panel.header-menu.duplicate', `Duplicate`), text: t('panel.header-menu.duplicate', `Duplicate`),
onClick: () => { onClick: () => {
DashboardInteractions.panelMenuItemClicked('duplicate');
dashboard.duplicatePanel(panel); dashboard.duplicatePanel(panel);
}, },
shortcut: 'p d', shortcut: 'p d',
@ -133,7 +129,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
moreSubMenu.push({ moreSubMenu.push({
text: t('panel.header-menu.copy', `Copy`), text: t('panel.header-menu.copy', `Copy`),
onClick: () => { onClick: () => {
DashboardInteractions.panelMenuItemClicked('copy');
dashboard.copyPanel(panel); dashboard.copyPanel(panel);
}, },
}); });
@ -144,7 +139,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
moreSubMenu.push({ moreSubMenu.push({
text: t('panel.header-menu.unlink-library-panel', `Unlink library panel`), text: t('panel.header-menu.unlink-library-panel', `Unlink library panel`),
onClick: () => { onClick: () => {
DashboardInteractions.panelMenuItemClicked('unlinkLibraryPanel');
dashboard.showModal( dashboard.showModal(
new UnlinkLibraryPanelModal({ new UnlinkLibraryPanelModal({
panelRef: parent.getRef(), panelRef: parent.getRef(),
@ -156,7 +150,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
moreSubMenu.push({ moreSubMenu.push({
text: t('panel.header-menu.replace-library-panel', `Replace library panel`), text: t('panel.header-menu.replace-library-panel', `Replace library panel`),
onClick: () => { onClick: () => {
DashboardInteractions.panelMenuItemClicked('replaceLibraryPanel');
dashboard.onShowAddLibraryPanelDrawer(parent.getRef()); dashboard.onShowAddLibraryPanelDrawer(parent.getRef());
}, },
}); });
@ -164,7 +157,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
moreSubMenu.push({ moreSubMenu.push({
text: t('panel.header-menu.create-library-panel', `Create library panel`), text: t('panel.header-menu.create-library-panel', `Create library panel`),
onClick: () => { onClick: () => {
DashboardInteractions.panelMenuItemClicked('createLibraryPanel');
dashboard.showModal( dashboard.showModal(
new ShareModal({ new ShareModal({
panelRef: panel.getRef(), panelRef: panel.getRef(),
@ -253,7 +245,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
text: t('panel.header-menu.remove', `Remove`), text: t('panel.header-menu.remove', `Remove`),
iconClassName: 'trash-alt', iconClassName: 'trash-alt',
onClick: () => { onClick: () => {
DashboardInteractions.panelMenuItemClicked('remove');
onRemovePanel(dashboard, panel); onRemovePanel(dashboard, panel);
}, },
shortcut: 'p r', shortcut: 'p r',
@ -278,7 +269,6 @@ async function getExploreMenuItem(panel: VizPanel): Promise<PanelMenuItem | unde
text: t('panel.header-menu.explore', `Explore`), text: t('panel.header-menu.explore', `Explore`),
iconClassName: 'compass', iconClassName: 'compass',
shortcut: 'p x', shortcut: 'p x',
onClick: () => DashboardInteractions.panelMenuItemClicked('explore'),
href: exploreUrl, href: exploreUrl,
}; };
} }
@ -297,7 +287,6 @@ function getInspectMenuItem(
onClick: (e) => { onClick: (e) => {
e.preventDefault(); e.preventDefault();
locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Data }); locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Data });
DashboardInteractions.panelMenuInspectClicked(InspectTab.Data);
}, },
}); });
@ -308,7 +297,6 @@ function getInspectMenuItem(
onClick: (e) => { onClick: (e) => {
e.preventDefault(); e.preventDefault();
locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Query }); locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Query });
DashboardInteractions.panelMenuInspectClicked(InspectTab.Query);
}, },
}); });
} }
@ -320,7 +308,6 @@ function getInspectMenuItem(
onClick: (e) => { onClick: (e) => {
e.preventDefault(); e.preventDefault();
locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.JSON }); locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.JSON });
DashboardInteractions.panelMenuInspectClicked(InspectTab.JSON);
}, },
}); });
@ -332,7 +319,6 @@ function getInspectMenuItem(
onClick: (e) => { onClick: (e) => {
if (!e.isDefaultPrevented()) { if (!e.isDefaultPrevented()) {
locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Data }); locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Data });
DashboardInteractions.panelMenuInspectClicked(InspectTab.Data);
} }
}, },
subMenu: inspectSubMenu.length > 0 ? inspectSubMenu : undefined, subMenu: inspectSubMenu.length > 0 ? inspectSubMenu : undefined,
@ -447,17 +433,12 @@ export function onRemovePanel(dashboard: DashboardScene, panel: VizPanel) {
} }
const onCreateAlert = async (panel: VizPanel) => { const onCreateAlert = async (panel: VizPanel) => {
DashboardInteractions.panelMenuItemClicked('create-alert');
const formValues = await scenesPanelToRuleFormValues(panel); const formValues = await scenesPanelToRuleFormValues(panel);
const ruleFormUrl = urlUtil.renderUrl('/alerting/new', { const ruleFormUrl = urlUtil.renderUrl('/alerting/new', {
defaults: JSON.stringify(formValues), defaults: JSON.stringify(formValues),
returnTo: location.pathname + location.search, returnTo: location.pathname + location.search,
}); });
locationService.push(ruleFormUrl); locationService.push(ruleFormUrl);
DashboardInteractions.panelMenuItemClicked('create-alert');
}; };
export function toggleVizPanelLegend(vizPanel: VizPanel): void { export function toggleVizPanelLegend(vizPanel: VizPanel): void {
@ -469,8 +450,6 @@ export function toggleVizPanelLegend(vizPanel: VizPanel): void {
}, },
}); });
} }
DashboardInteractions.panelMenuItemClicked('toggleLegend');
} }
function hasLegendOptions(optionsWithLegend: unknown): optionsWithLegend is OptionsWithLegend { function hasLegendOptions(optionsWithLegend: unknown): optionsWithLegend is OptionsWithLegend {
@ -482,5 +461,4 @@ const onInspectPanel = (vizPanel: VizPanel, tab?: InspectTab) => {
inspect: vizPanel.state.key, inspect: vizPanel.state.key,
inspectTab: tab, inspectTab: tab,
}); });
DashboardInteractions.panelMenuInspectClicked(tab ?? InspectTab.Data);
}; };

View File

@ -521,9 +521,6 @@ function registerPanelInteractionsReporter(scene: DashboardScene) {
case 'panel-cancel-query-clicked': case 'panel-cancel-query-clicked':
DashboardInteractions.panelCancelQueryClicked(); DashboardInteractions.panelCancelQueryClicked();
break; break;
case 'panel-menu-shown':
DashboardInteractions.panelMenuShown();
break;
} }
}); });
} }

View File

@ -1,5 +1,4 @@
import { reportInteraction } from '@grafana/runtime'; import { reportInteraction } from '@grafana/runtime';
import { InspectTab } from 'app/features/inspector/types';
let isScenesContextSet = false; let isScenesContextSet = false;
@ -9,30 +8,6 @@ export const DashboardInteractions = {
reportDashboardInteraction('init_dashboard_completed', { ...properties }); reportDashboardInteraction('init_dashboard_completed', { ...properties });
}, },
// Panel interactions:
panelMenuShown: (properties?: Record<string, unknown>) => {
reportDashboardInteraction('panelheader_menu', { ...properties, item: 'menu' });
},
panelMenuItemClicked: (
item:
| 'view'
| 'edit'
| 'share'
| 'createLibraryPanel'
| 'unlinkLibraryPanel'
| 'replaceLibraryPanel'
| 'duplicate'
| 'copy'
| 'remove'
| 'explore'
| 'toggleLegend'
| 'create-alert'
) => {
reportDashboardInteraction('panelheader_menu', { item });
},
panelMenuInspectClicked(tab: InspectTab) {
reportDashboardInteraction('panelheader_menu', { item: 'inspect', tab });
},
panelLinkClicked: (properties?: Record<string, unknown>) => { panelLinkClicked: (properties?: Record<string, unknown>) => {
reportDashboardInteraction('panelheader_datalink_clicked', properties); reportDashboardInteraction('panelheader_datalink_clicked', properties);
}, },
@ -43,6 +18,20 @@ export const DashboardInteractions = {
reportDashboardInteraction('panelheader_cancelquery_clicked', properties); reportDashboardInteraction('panelheader_cancelquery_clicked', properties);
}, },
// Dashboard interactions from toolbar
toolbarFavoritesClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'favorites' });
},
toolbarSettingsClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'settings' });
},
toolbarShareClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'share' });
},
toolbarAddClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'add' });
},
// Sharing interactions: // Sharing interactions:
sharingCategoryClicked: (properties?: Record<string, unknown>) => { sharingCategoryClicked: (properties?: Record<string, unknown>) => {
reportDashboardInteraction('sharing_category_clicked', properties); reportDashboardInteraction('sharing_category_clicked', properties);
@ -111,35 +100,6 @@ export const DashboardInteractions = {
toolbarAddButtonClicked: (properties?: Record<string, unknown>) => { toolbarAddButtonClicked: (properties?: Record<string, unknown>) => {
reportDashboardInteraction('toolbar_add_clicked', properties); reportDashboardInteraction('toolbar_add_clicked', properties);
}, },
toolbarFavoritesClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'favorites' });
},
toolbarSettingsClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'settings' });
},
toolbarRefreshClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'refresh' });
},
toolbarTimePickerClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'time_picker' });
},
toolbarZoomClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'zoom_out_time_range' });
},
toolbarShareClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'share' });
},
toolbarSaveClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'save' });
},
toolbarSaveAsClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'save_as' });
},
toolbarAddClick: () => {
reportDashboardInteraction('toolbar_actions_clicked', { item: 'add' });
},
setScenesContext: () => { setScenesContext: () => {
isScenesContextSet = true; isScenesContextSet = true;

View File

@ -270,14 +270,7 @@ export const DashNav = memo<Props>((props) => {
return null; return null;
} }
return ( return (
<DashNavTimeControls <DashNavTimeControls dashboard={dashboard} onChangeTimeZone={updateTimeZoneForSession} key="time-controls" />
dashboard={dashboard}
onChangeTimeZone={updateTimeZoneForSession}
onToolbarRefreshClick={DashboardInteractions.toolbarRefreshClick}
onToolbarZoomClick={DashboardInteractions.toolbarZoomClick}
onToolbarTimePickerClick={DashboardInteractions.toolbarTimePickerClick}
key="time-controls"
/>
); );
}; };
@ -315,7 +308,6 @@ export const DashNav = memo<Props>((props) => {
tooltip={t('dashboard.toolbar.save', 'Save dashboard')} tooltip={t('dashboard.toolbar.save', 'Save dashboard')}
icon="save" icon="save"
onClick={() => { onClick={() => {
DashboardInteractions.toolbarSaveClick();
showModal(SaveDashboardDrawer, { showModal(SaveDashboardDrawer, {
dashboard, dashboard,
onDismiss: hideModal, onDismiss: hideModal,
@ -343,8 +335,8 @@ export const DashNav = memo<Props>((props) => {
if (canEdit && !isFullscreen) { if (canEdit && !isFullscreen) {
buttons.push( buttons.push(
<AddPanelButton <AddPanelButton
dashboard={dashboard}
onToolbarAddMenuOpen={DashboardInteractions.toolbarAddClick} onToolbarAddMenuOpen={DashboardInteractions.toolbarAddClick}
dashboard={dashboard}
key="panel-add-dropdown" key="panel-add-dropdown"
/> />
); );

View File

@ -209,7 +209,6 @@ export class PanelChromeAngularUnconnected extends PureComponent<Props, State> {
hoverHeader={panelChromeProps.hasOverlayHeader()} hoverHeader={panelChromeProps.hasOverlayHeader()}
displayMode={transparent ? 'transparent' : 'default'} displayMode={transparent ? 'transparent' : 'default'}
onCancelQuery={panelChromeProps.onCancelQuery} onCancelQuery={panelChromeProps.onCancelQuery}
onOpenMenu={panelChromeProps.onOpenMenu}
> >
{() => <div ref={(element) => (this.element = element)} className="panel-height-helper" />} {() => <div ref={(element) => (this.element = element)} className="panel-height-helper" />}
</PanelChrome> </PanelChrome>

View File

@ -587,7 +587,6 @@ export class PanelStateWrapper extends PureComponent<Props, State> {
hoverHeader={panelChromeProps.hasOverlayHeader()} hoverHeader={panelChromeProps.hasOverlayHeader()}
displayMode={transparent ? 'transparent' : 'default'} displayMode={transparent ? 'transparent' : 'default'}
onCancelQuery={panelChromeProps.onCancelQuery} onCancelQuery={panelChromeProps.onCancelQuery}
onOpenMenu={panelChromeProps.onOpenMenu}
onFocus={() => this.setPanelAttention()} onFocus={() => this.setPanelAttention()}
onMouseEnter={() => this.setPanelAttention()} onMouseEnter={() => this.setPanelAttention()}
onMouseMove={() => this.debouncedSetPanelAttention()} onMouseMove={() => this.debouncedSetPanelAttention()}

View File

@ -113,10 +113,6 @@ export function getPanelChromeProps(props: CommonProps) {
const title = props.panel.getDisplayTitle(); const title = props.panel.getDisplayTitle();
const onOpenMenu = () => {
DashboardInteractions.panelMenuShown();
};
return { return {
hasOverlayHeader, hasOverlayHeader,
onShowPanelDescription, onShowPanelDescription,
@ -129,6 +125,5 @@ export function getPanelChromeProps(props: CommonProps) {
dragClass, dragClass,
title, title,
titleItems, titleItems,
onOpenMenu,
}; };
} }

View File

@ -21,7 +21,6 @@ import {
toggleLegend, toggleLegend,
unlinkLibraryPanel, unlinkLibraryPanel,
} from 'app/features/dashboard/utils/panel'; } from 'app/features/dashboard/utils/panel';
import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
import { InspectTab } from 'app/features/inspector/types'; import { InspectTab } from 'app/features/inspector/types';
import { isPanelModelLibraryPanel } from 'app/features/library-panels/guard'; import { isPanelModelLibraryPanel } from 'app/features/library-panels/guard';
import { createExtensionSubMenu } from 'app/features/plugins/extensions/utils'; import { createExtensionSubMenu } from 'app/features/plugins/extensions/utils';
@ -43,7 +42,6 @@ export function getPanelMenu(
locationService.partial({ locationService.partial({
viewPanel: panel.id, viewPanel: panel.id,
}); });
DashboardInteractions.panelMenuItemClicked('view');
}; };
const onEditPanel = (event: React.MouseEvent) => { const onEditPanel = (event: React.MouseEvent) => {
@ -51,26 +49,21 @@ export function getPanelMenu(
locationService.partial({ locationService.partial({
editPanel: panel.id, editPanel: panel.id,
}); });
DashboardInteractions.panelMenuItemClicked('edit');
}; };
const onSharePanel = (event: React.MouseEvent) => { const onSharePanel = (event: React.MouseEvent) => {
event.preventDefault(); event.preventDefault();
sharePanel(dashboard, panel); sharePanel(dashboard, panel);
DashboardInteractions.panelMenuItemClicked('share');
}; };
const onAddLibraryPanel = (event: React.MouseEvent) => { const onAddLibraryPanel = (event: React.MouseEvent) => {
event.preventDefault(); event.preventDefault();
addLibraryPanel(dashboard, panel); addLibraryPanel(dashboard, panel);
DashboardInteractions.panelMenuItemClicked('createLibraryPanel');
}; };
const onUnlinkLibraryPanel = (event: React.MouseEvent) => { const onUnlinkLibraryPanel = (event: React.MouseEvent) => {
event.preventDefault(); event.preventDefault();
unlinkLibraryPanel(panel); unlinkLibraryPanel(panel);
DashboardInteractions.panelMenuItemClicked('unlinkLibraryPanel');
}; };
const onInspectPanel = (tab?: InspectTab) => { const onInspectPanel = (tab?: InspectTab) => {
@ -78,7 +71,6 @@ export function getPanelMenu(
inspect: panel.id, inspect: panel.id,
inspectTab: tab, inspectTab: tab,
}); });
DashboardInteractions.panelMenuInspectClicked(tab ?? InspectTab.Data);
}; };
const onMore = (event: React.MouseEvent) => { const onMore = (event: React.MouseEvent) => {
@ -88,19 +80,16 @@ export function getPanelMenu(
const onDuplicatePanel = (event: React.MouseEvent) => { const onDuplicatePanel = (event: React.MouseEvent) => {
event.preventDefault(); event.preventDefault();
duplicatePanel(dashboard, panel); duplicatePanel(dashboard, panel);
DashboardInteractions.panelMenuItemClicked('duplicate');
}; };
const onCopyPanel = (event: React.MouseEvent) => { const onCopyPanel = (event: React.MouseEvent) => {
event.preventDefault(); event.preventDefault();
copyPanel(panel); copyPanel(panel);
DashboardInteractions.panelMenuItemClicked('copy');
}; };
const onRemovePanel = (event: React.MouseEvent) => { const onRemovePanel = (event: React.MouseEvent) => {
event.preventDefault(); event.preventDefault();
removePanel(dashboard, panel, true); removePanel(dashboard, panel, true);
DashboardInteractions.panelMenuItemClicked('remove');
}; };
const onNavigateToExplore = (event: React.MouseEvent) => { const onNavigateToExplore = (event: React.MouseEvent) => {
@ -114,13 +103,11 @@ export function getPanelMenu(
openInNewWindow, openInNewWindow,
}) as any }) as any
); );
DashboardInteractions.panelMenuItemClicked('explore');
}; };
const onToggleLegend = (event: React.MouseEvent) => { const onToggleLegend = (event: React.MouseEvent) => {
event.preventDefault(); event.preventDefault();
toggleLegend(panel); toggleLegend(panel);
DashboardInteractions.panelMenuItemClicked('toggleLegend');
}; };
const menu: PanelMenuItem[] = []; const menu: PanelMenuItem[] = [];
@ -224,7 +211,6 @@ export function getPanelMenu(
const onCreateAlert = (event: React.MouseEvent) => { const onCreateAlert = (event: React.MouseEvent) => {
event.preventDefault(); event.preventDefault();
createAlert(); createAlert();
DashboardInteractions.panelMenuItemClicked('create-alert');
}; };
const subMenu: PanelMenuItem[] = []; const subMenu: PanelMenuItem[] = [];