Navigation: Display Starred dashboards in the Navbar (#51038)

* remove feature toggle, add empty state and fix bug with initial starring

* Extract empty message into lingui

* remove full stop

* add empty message in the backend

* remove unused import

* translate starred + empty starred states

* betterer changes
This commit is contained in:
Ashley Harrison
2022-06-27 15:41:00 +01:00
committed by GitHub
parent 4a9872d108
commit ee3f4f1709
16 changed files with 110 additions and 50 deletions

View File

@@ -1,4 +1,5 @@
import { css } from '@emotion/css';
import { useLingui } from '@lingui/react';
import { useMenu } from '@react-aria/menu';
import { mergeProps } from '@react-aria/utils';
import { useTreeState } from '@react-stately/tree';
@@ -11,6 +12,7 @@ import { useTheme2 } from '@grafana/ui';
import { NavBarItemMenuItem } from './NavBarItemMenuItem';
import { NavBarScrollContainer } from './NavBarScrollContainer';
import { useNavBarItemMenuContext } from './context';
import menuItemTranslations from './navBarItem-translations';
import { getNavModelItemKey } from './utils';
export interface NavBarItemMenuProps extends SpectrumMenuProps<NavModelItem> {
@@ -21,6 +23,7 @@ export interface NavBarItemMenuProps extends SpectrumMenuProps<NavModelItem> {
export function NavBarItemMenu(props: NavBarItemMenuProps): ReactElement | null {
const { reverseMenuDirection, adjustHeightForBorder, disabledKeys, onNavigate, ...rest } = props;
const { i18n } = useLingui();
const contextProps = useNavBarItemMenuContext();
const completeProps = {
...mergeProps(contextProps, rest),
@@ -58,6 +61,15 @@ export function NavBarItemMenu(props: NavBarItemMenuProps): ReactElement | null
<NavBarItemMenuItem key={getNavModelItemKey(item.value)} item={item} state={state} onNavigate={onNavigate} />
));
if (itemComponents.length === 0 && section.value.emptyMessageId) {
const emptyMessageTranslated = i18n._(menuItemTranslations[section.value.emptyMessageId]);
itemComponents.push(
<div key="empty-message" className={styles.emptyMessage}>
{emptyMessageTranslated}
</div>
);
}
const subTitleComponent = menuSubTitle && (
<li key={menuSubTitle} className={styles.subtitle}>
{menuSubTitle}
@@ -105,5 +117,9 @@ function getStyles(theme: GrafanaTheme2, reverseDirection?: boolean) {
text-align: left;
white-space: nowrap;
`,
emptyMessage: css`
font-style: italic;
padding: ${theme.spacing(0.5, 2)};
`,
};
}

View File

@@ -88,11 +88,5 @@ function getStyles(theme: GrafanaTheme2, isFocused: boolean, isSection: boolean)
transition: none;
}
`,
upgradeBoxContainer: css`
padding: ${theme.spacing(1)};
`,
upgradeBox: css`
width: 300px;
`,
};
}

View File

@@ -1,4 +1,5 @@
import { css, cx } from '@emotion/css';
import { useLingui } from '@lingui/react';
import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { OverlayContainer, useOverlay } from '@react-aria/overlays';
@@ -16,6 +17,7 @@ import { NavBarItemWithoutMenu } from './NavBarItemWithoutMenu';
import { NavBarMenuItem } from './NavBarMenuItem';
import { NavBarToggle } from './NavBarToggle';
import { NavFeatureHighlight } from './NavFeatureHighlight';
import menuItemTranslations from './navBarItem-translations';
import { isMatchOrChildMatch } from './utils';
const MENU_WIDTH = '350px';
@@ -35,6 +37,7 @@ export function NavBarMenu({ activeItem, isOpen, navItems, onClose, setMenuAnima
const animStyles = getAnimStyles(theme, ANIMATION_DURATION);
const ref = useRef(null);
const { dialogProps } = useDialog({}, ref);
const { overlayProps, underlayProps } = useOverlay(
{
isDismissable: true,
@@ -226,6 +229,7 @@ function NavItem({
activeItem?: NavModelItem;
onClose: () => void;
}) {
const { i18n } = useLingui();
const styles = useStyles2(getNavItemStyles);
if (linkHasChildren(link)) {
@@ -255,6 +259,15 @@ function NavItem({
</ul>
</CollapsibleNavItem>
);
} else if (link.emptyMessageId) {
const emptyMessageTranslated = i18n._(menuItemTranslations[link.emptyMessageId]);
return (
<CollapsibleNavItem onClose={onClose} link={link} isActive={isMatchOrChildMatch(link, activeItem)}>
<ul className={styles.children}>
<div className={styles.emptyMessage}>{emptyMessageTranslated}</div>
</ul>
</CollapsibleNavItem>
);
} else {
const FeatureHighlightWrapper = link.highlightText ? NavFeatureHighlight : React.Fragment;
return (
@@ -326,6 +339,11 @@ const getNavItemStyles = (theme: GrafanaTheme2) => ({
justifySelf: 'start',
padding: theme.spacing(0.5, 4.25, 0.5, 0.5),
}),
emptyMessage: css({
color: theme.colors.text.secondary,
fontStyle: 'italic',
padding: theme.spacing(1, 1.5),
}),
});
function CollapsibleNavItem({

View File

@@ -15,6 +15,8 @@ const TRANSLATED_MENU_ITEMS: Record<string, MessageDescriptor> = {
import: defineMessage({ id: 'nav.create-import', message: 'Import' }),
alert: defineMessage({ id: 'nav.create-alert', message: 'New alert rule' }),
starred: defineMessage({ id: 'nav.starred', message: 'Starred' }),
'starred-empty': defineMessage({ id: 'nav.starred-empty', message: 'Your starred dashboards will appear here' }),
dashboards: defineMessage({ id: 'nav.dashboards', message: 'Dashboards' }),
'manage-dashboards': defineMessage({ id: 'nav.manage-dashboards', message: 'Browse' }),
playlists: defineMessage({ id: 'nav.playlists', message: 'Playlists' }),

View File

@@ -12,29 +12,36 @@ const navTreeSlice = createSlice({
setStarred: (state, action: PayloadAction<{ id: string; title: string; url: string; isStarred: boolean }>) => {
const starredItems = state.find((navItem) => navItem.id === 'starred');
const { id, title, url, isStarred } = action.payload;
if (isStarred) {
const newStarredItem: NavModelItem = {
id,
text: title,
url,
};
starredItems?.children?.push(newStarredItem);
starredItems?.children?.sort((a, b) => a.text.localeCompare(b.text));
} else {
const index = starredItems?.children?.findIndex((item) => item.id === id) ?? -1;
if (index > -1) {
starredItems?.children?.splice(index, 1);
if (starredItems) {
if (isStarred) {
if (!starredItems.children) {
starredItems.children = [];
}
const newStarredItem: NavModelItem = {
id,
text: title,
url,
};
starredItems.children.push(newStarredItem);
starredItems.children.sort((a, b) => a.text.localeCompare(b.text));
} else {
const index = starredItems.children?.findIndex((item) => item.id === id) ?? -1;
if (index > -1) {
starredItems?.children?.splice(index, 1);
}
}
}
},
updateDashboardName: (state, action: PayloadAction<{ id: string; title: string; url: string }>) => {
const { id, title, url } = action.payload;
const starredItems = state.find((navItem) => navItem.id === 'starred');
const navItem = starredItems?.children?.find((navItem) => navItem.id === id);
if (navItem) {
navItem.text = title;
navItem.url = url;
starredItems?.children?.sort((a, b) => a.text.localeCompare(b.text));
if (starredItems) {
const navItem = starredItems.children?.find((navItem) => navItem.id === id);
if (navItem) {
navItem.text = title;
navItem.url = url;
starredItems.children?.sort((a, b) => a.text.localeCompare(b.text));
}
}
},
},

View File

@@ -190,6 +190,14 @@ msgstr "Sign out"
msgid "nav.snapshots"
msgstr "Snapshots"
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.starred"
msgstr "Starred"
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.starred-empty"
msgstr "Your starred dashboards will appear here"
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.teams"
msgstr "Teams"

View File

@@ -190,6 +190,14 @@ msgstr ""
msgid "nav.snapshots"
msgstr ""
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.starred"
msgstr ""
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.starred-empty"
msgstr ""
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.teams"
msgstr ""

View File

@@ -190,6 +190,14 @@ msgstr ""
msgid "nav.snapshots"
msgstr ""
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.starred"
msgstr ""
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.starred-empty"
msgstr ""
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.teams"
msgstr ""

View File

@@ -190,6 +190,14 @@ msgstr ""
msgid "nav.snapshots"
msgstr ""
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.starred"
msgstr ""
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.starred-empty"
msgstr ""
#: public/app/core/components/NavBar/navBarItem-translations.ts
msgid "nav.teams"
msgstr ""