mirror of
https://github.com/grafana/grafana.git
synced 2025-09-17 03:23:16 +08:00
Bookmarks: Store URLs instead of ids (#91121)
This commit is contained in:
@ -53,7 +53,7 @@ Content-Type: application/json
|
|||||||
`PUT /api/user/preferences`
|
`PUT /api/user/preferences`
|
||||||
|
|
||||||
**Example Request**:
|
**Example Request**:
|
||||||
|
|
||||||
```http
|
```http
|
||||||
PUT /api/user/preferences HTTP/1.1
|
PUT /api/user/preferences HTTP/1.1
|
||||||
Accept: application/json
|
Accept: application/json
|
||||||
@ -142,7 +142,7 @@ Content-Type: application/json
|
|||||||
Update one or more preferences without modifying the others.
|
Update one or more preferences without modifying the others.
|
||||||
|
|
||||||
`PATCH /api/org/preferences`
|
`PATCH /api/org/preferences`
|
||||||
|
|
||||||
**Example Request**:
|
**Example Request**:
|
||||||
|
|
||||||
```http
|
```http
|
||||||
|
@ -49,7 +49,7 @@ lineage: schemas: [{
|
|||||||
} @cuetsy(kind="interface")
|
} @cuetsy(kind="interface")
|
||||||
|
|
||||||
#NavbarPreference: {
|
#NavbarPreference: {
|
||||||
bookmarkIds: [...string]
|
bookmarkUrls: [...string]
|
||||||
} @cuetsy(kind="interface")
|
} @cuetsy(kind="interface")
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
|
@ -22,11 +22,11 @@ export interface CookiePreferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface NavbarPreference {
|
export interface NavbarPreference {
|
||||||
bookmarkIds: Array<string>;
|
bookmarkUrls: Array<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultNavbarPreference: Partial<NavbarPreference> = {
|
export const defaultNavbarPreference: Partial<NavbarPreference> = {
|
||||||
bookmarkIds: [],
|
bookmarkUrls: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,7 +18,7 @@ type CookiePreferences struct {
|
|||||||
|
|
||||||
// NavbarPreference defines model for NavbarPreference.
|
// NavbarPreference defines model for NavbarPreference.
|
||||||
type NavbarPreference struct {
|
type NavbarPreference struct {
|
||||||
BookmarkIds []string `json:"bookmarkIds"`
|
BookmarkUrls []string `json:"bookmarkUrls"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryHistoryPreference defines model for QueryHistoryPreference.
|
// QueryHistoryPreference defines model for QueryHistoryPreference.
|
||||||
|
@ -338,11 +338,11 @@ func (s *ServiceImpl) buildStarredItemsNavLinks(c *contextmodel.ReqContext) ([]*
|
|||||||
func (s *ServiceImpl) buildBookmarksNavLinks(prefs *pref.Preference, treeRoot *navtree.NavTreeRoot) []*navtree.NavLink {
|
func (s *ServiceImpl) buildBookmarksNavLinks(prefs *pref.Preference, treeRoot *navtree.NavTreeRoot) []*navtree.NavLink {
|
||||||
bookmarksChildNavs := []*navtree.NavLink{}
|
bookmarksChildNavs := []*navtree.NavLink{}
|
||||||
|
|
||||||
bookmarkIds := prefs.JSONData.Navbar.BookmarkIds
|
bookmarkUrls := prefs.JSONData.Navbar.BookmarkUrls
|
||||||
|
|
||||||
if len(bookmarkIds) > 0 {
|
if len(bookmarkUrls) > 0 {
|
||||||
for _, id := range bookmarkIds {
|
for _, url := range bookmarkUrls {
|
||||||
item := treeRoot.FindById(id)
|
item := treeRoot.FindByURL(url)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
bookmarksChildNavs = append(bookmarksChildNavs, &navtree.NavLink{
|
bookmarksChildNavs = append(bookmarksChildNavs, &navtree.NavLink{
|
||||||
Id: item.Id,
|
Id: item.Id,
|
||||||
|
@ -98,7 +98,7 @@ type QueryHistoryPreference struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type NavbarPreference struct {
|
type NavbarPreference struct {
|
||||||
BookmarkIds []string `json:"bookmarkIds"`
|
BookmarkUrls []string `json:"bookmarkUrls"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *PreferenceJSONData) FromDB(data []byte) error {
|
func (j *PreferenceJSONData) FromDB(data []byte) error {
|
||||||
|
@ -97,11 +97,11 @@ func GetPreferencesFor(ctx context.Context,
|
|||||||
dto.Language = &preference.JSONData.Language
|
dto.Language = &preference.JSONData.Language
|
||||||
}
|
}
|
||||||
|
|
||||||
if preference.JSONData.Navbar.BookmarkIds != nil {
|
if preference.JSONData.Navbar.BookmarkUrls != nil {
|
||||||
dto.Navbar = &preferences.NavbarPreference{
|
dto.Navbar = &preferences.NavbarPreference{
|
||||||
BookmarkIds: []string{},
|
BookmarkUrls: []string{},
|
||||||
}
|
}
|
||||||
dto.Navbar.BookmarkIds = preference.JSONData.Navbar.BookmarkIds
|
dto.Navbar.BookmarkUrls = preference.JSONData.Navbar.BookmarkUrls
|
||||||
}
|
}
|
||||||
|
|
||||||
if preference.JSONData.QueryHistory.HomeTab != "" {
|
if preference.JSONData.QueryHistory.HomeTab != "" {
|
||||||
|
@ -71,8 +71,8 @@ func (s *Service) GetWithDefaults(ctx context.Context, query *pref.GetPreference
|
|||||||
res.JSONData.QueryHistory.HomeTab = p.JSONData.QueryHistory.HomeTab
|
res.JSONData.QueryHistory.HomeTab = p.JSONData.QueryHistory.HomeTab
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.JSONData.Navbar.BookmarkIds != nil {
|
if p.JSONData.Navbar.BookmarkUrls != nil {
|
||||||
res.JSONData.Navbar.BookmarkIds = p.JSONData.Navbar.BookmarkIds
|
res.JSONData.Navbar.BookmarkUrls = p.JSONData.Navbar.BookmarkUrls
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.JSONData.CookiePreferences != nil {
|
if p.JSONData.CookiePreferences != nil {
|
||||||
@ -174,11 +174,11 @@ func (s *Service) Patch(ctx context.Context, cmd *pref.PatchPreferenceCommand) e
|
|||||||
preference.JSONData.Language = *cmd.Language
|
preference.JSONData.Language = *cmd.Language
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Navbar != nil && cmd.Navbar.BookmarkIds != nil {
|
if cmd.Navbar != nil && cmd.Navbar.BookmarkUrls != nil {
|
||||||
if preference.JSONData == nil {
|
if preference.JSONData == nil {
|
||||||
preference.JSONData = &pref.PreferenceJSONData{}
|
preference.JSONData = &pref.PreferenceJSONData{}
|
||||||
}
|
}
|
||||||
preference.JSONData.Navbar.BookmarkIds = cmd.Navbar.BookmarkIds
|
preference.JSONData.Navbar.BookmarkUrls = cmd.Navbar.BookmarkUrls
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.QueryHistory != nil {
|
if cmd.QueryHistory != nil {
|
||||||
|
@ -17112,7 +17112,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "NavbarPreference defines model for NavbarPreference.",
|
"title": "NavbarPreference defines model for NavbarPreference.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"bookmarkIds": {
|
"bookmarkUrls": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -54,29 +54,28 @@ export const MegaMenu = memo(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isPinned = useCallback(
|
const isPinned = useCallback(
|
||||||
(id?: string) => {
|
(url?: string) => {
|
||||||
if (!id || !pinnedItems?.length) {
|
if (!url || !pinnedItems?.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return pinnedItems?.includes(id);
|
return pinnedItems?.includes(url);
|
||||||
},
|
},
|
||||||
[pinnedItems]
|
[pinnedItems]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onPinItem = (item: NavModelItem) => {
|
const onPinItem = (item: NavModelItem) => {
|
||||||
const id = item.id;
|
const url = item.url;
|
||||||
if (id && config.featureToggles.pinNavItems) {
|
if (url && config.featureToggles.pinNavItems) {
|
||||||
const navItem = navTree.find((item) => item.id === id);
|
const isSaved = isPinned(url);
|
||||||
const isSaved = isPinned(id);
|
const newItems = isSaved ? pinnedItems.filter((i) => url !== i) : [...pinnedItems, url];
|
||||||
const newItems = isSaved ? pinnedItems.filter((i) => id !== i) : [...pinnedItems, id];
|
|
||||||
const interactionName = isSaved ? 'grafana_nav_item_unpinned' : 'grafana_nav_item_pinned';
|
const interactionName = isSaved ? 'grafana_nav_item_unpinned' : 'grafana_nav_item_pinned';
|
||||||
reportInteraction(interactionName, {
|
reportInteraction(interactionName, {
|
||||||
path: navItem?.url ?? id,
|
path: url,
|
||||||
});
|
});
|
||||||
patchPreferences({
|
patchPreferences({
|
||||||
patchPrefsCmd: {
|
patchPrefsCmd: {
|
||||||
navbar: {
|
navbar: {
|
||||||
bookmarkIds: newItems,
|
bookmarkUrls: newItems,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
|
@ -104,9 +104,8 @@ export function MegaMenuItem({ link, activeItem, level = 0, onClick, onPin, isPi
|
|||||||
}}
|
}}
|
||||||
target={link.target}
|
target={link.target}
|
||||||
url={link.url}
|
url={link.url}
|
||||||
id={link.id}
|
|
||||||
onPin={() => onPin(link)}
|
onPin={() => onPin(link)}
|
||||||
isPinned={isPinned(link.id)}
|
isPinned={isPinned(link.url)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cx(styles.labelWrapper, {
|
className={cx(styles.labelWrapper, {
|
||||||
|
@ -13,12 +13,11 @@ export interface Props {
|
|||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
target?: HTMLAnchorElement['target'];
|
target?: HTMLAnchorElement['target'];
|
||||||
url: string;
|
url: string;
|
||||||
id?: string;
|
|
||||||
onPin: (id?: string) => void;
|
onPin: (id?: string) => void;
|
||||||
isPinned?: boolean;
|
isPinned?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MegaMenuItemText({ children, isActive, onClick, target, url, id, onPin, isPinned }: Props) {
|
export function MegaMenuItemText({ children, isActive, onClick, target, url, onPin, isPinned }: Props) {
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
const styles = getStyles(theme, isActive);
|
const styles = getStyles(theme, isActive);
|
||||||
const LinkComponent = !target && url.startsWith('/') ? Link : 'a';
|
const LinkComponent = !target && url.startsWith('/') ? Link : 'a';
|
||||||
@ -51,12 +50,12 @@ export function MegaMenuItemText({ children, isActive, onClick, target, url, id,
|
|||||||
>
|
>
|
||||||
{linkContent}
|
{linkContent}
|
||||||
</LinkComponent>
|
</LinkComponent>
|
||||||
{config.featureToggles.pinNavItems && id && id !== 'bookmarks' && (
|
{config.featureToggles.pinNavItems && url && url !== '/bookmarks' && (
|
||||||
<IconButton
|
<IconButton
|
||||||
name="bookmark"
|
name="bookmark"
|
||||||
className={'pin-icon'}
|
className={'pin-icon'}
|
||||||
iconType={isPinned ? 'solid' : 'default'}
|
iconType={isPinned ? 'solid' : 'default'}
|
||||||
onClick={() => onPin(id)}
|
onClick={() => onPin(url)}
|
||||||
aria-label={
|
aria-label={
|
||||||
isPinned
|
isPinned
|
||||||
? t('navigation.item.remove-bookmark', 'Remove from Bookmarks')
|
? t('navigation.item.remove-bookmark', 'Remove from Bookmarks')
|
||||||
|
@ -5,7 +5,7 @@ import { useGetUserPreferencesQuery } from 'app/features/preferences/api';
|
|||||||
|
|
||||||
export const usePinnedItems = () => {
|
export const usePinnedItems = () => {
|
||||||
const preferences = useGetUserPreferencesQuery();
|
const preferences = useGetUserPreferencesQuery();
|
||||||
const pinnedItems = useMemo(() => preferences.data?.navbar?.bookmarkIds || [], [preferences]);
|
const pinnedItems = useMemo(() => preferences.data?.navbar?.bookmarkUrls || [], [preferences]);
|
||||||
|
|
||||||
if (config.featureToggles.pinNavItems) {
|
if (config.featureToggles.pinNavItems) {
|
||||||
return pinnedItems;
|
return pinnedItems;
|
||||||
|
@ -73,7 +73,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
|
|||||||
weekStart: '',
|
weekStart: '',
|
||||||
language: '',
|
language: '',
|
||||||
queryHistory: { homeTab: '' },
|
queryHistory: { homeTab: '' },
|
||||||
navbar: { bookmarkIds: [] },
|
navbar: { bookmarkUrls: [] },
|
||||||
};
|
};
|
||||||
|
|
||||||
this.themeOptions = getBuiltInThemes(config.featureToggles.extraThemes).map((theme) => ({
|
this.themeOptions = getBuiltInThemes(config.featureToggles.extraThemes).map((theme) => ({
|
||||||
|
@ -71,7 +71,7 @@ const navTreeSlice = createSlice({
|
|||||||
};
|
};
|
||||||
bookmarks.children.push(newBookmark);
|
bookmarks.children.push(newBookmark);
|
||||||
} else {
|
} else {
|
||||||
bookmarks.children = bookmarks.children?.filter((i) => i.id !== item.id) ?? [];
|
bookmarks.children = bookmarks.children?.filter((i) => i.url !== item.url) ?? [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -38,7 +38,7 @@ export type CookiePreferencesDefinesModelForCookiePreferences = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
export type NavbarPreferenceDefinesModelForNavbarPreference = {
|
export type NavbarPreferenceDefinesModelForNavbarPreference = {
|
||||||
bookmarkIds?: string[];
|
bookmarkUrls?: string[];
|
||||||
};
|
};
|
||||||
export type QueryHistoryPreferenceDefinesModelForQueryHistoryPreference = {
|
export type QueryHistoryPreferenceDefinesModelForQueryHistoryPreference = {
|
||||||
/** HomeTab one of: '' | 'query' | 'starred'; */
|
/** HomeTab one of: '' | 'query' | 'starred'; */
|
||||||
|
@ -7188,7 +7188,7 @@
|
|||||||
},
|
},
|
||||||
"NavbarPreference": {
|
"NavbarPreference": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"bookmarkIds": {
|
"bookmarkUrls": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user