Skip to content

Commit 5c060cc

Browse files
Make favorite queries/dashboard order by starred at(favorited at)
1 parent 4357ea5 commit 5c060cc

File tree

8 files changed

+64
-22
lines changed

8 files changed

+64
-22
lines changed

client/app/components/items-list/ItemsList.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export interface ItemsListWrappedComponentProps<I, P = any> {
9393
export function wrap<I, P = any>(
9494
WrappedComponent: React.ComponentType<ItemsListWrappedComponentProps<I>>,
9595
createItemsSource: () => ItemsSource,
96-
createStateStorage: () => StateStorage
96+
createStateStorage: ( { ...props }) => StateStorage
9797
) {
9898
class ItemsListWrapper extends React.Component<ItemsListWrapperProps, ItemsListWrapperState<I, P>> {
9999
private _itemsSource: ItemsSource;
@@ -116,7 +116,7 @@ export function wrap<I, P = any>(
116116
constructor(props: ItemsListWrapperProps) {
117117
super(props);
118118

119-
const stateStorage = createStateStorage();
119+
const stateStorage = createStateStorage({ ...props });
120120
const itemsSource = createItemsSource();
121121
this._itemsSource = itemsSource;
122122

client/app/pages/dashboards/DashboardList.jsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,19 @@ function DashboardListExtraActions(props) {
8181
}
8282

8383
function DashboardList({ controller }) {
84+
let usedListColumns = listColumns;
85+
if (controller.params.currentPage === "favorites") {
86+
usedListColumns = [
87+
...usedListColumns,
88+
Columns.dateTime.sortable({ title: "Starred At", field: "starred_at", width: "1%" }),
89+
];
90+
}
8491
const {
8592
areExtraActionsAvailable,
8693
listColumns: tableColumns,
8794
Component: ExtraActionsComponent,
8895
selectedItems,
89-
} = useItemsListExtraActions(controller, listColumns, DashboardListExtraActions);
96+
} = useItemsListExtraActions(controller, usedListColumns, DashboardListExtraActions);
9097

9198
return (
9299
<div className="page-dashboard-list">
@@ -173,7 +180,7 @@ const DashboardListPage = itemsList(
173180
return item => new Dashboard(item);
174181
},
175182
}),
176-
() => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true })
183+
({ ...props }) => new UrlStateStorage({ orderByField: props.orderByField ?? "created_at", orderByReverse: true })
177184
);
178185

179186
routes.register(
@@ -189,7 +196,7 @@ routes.register(
189196
routeWithUserSession({
190197
path: "/dashboards/favorites",
191198
title: "Favorite Dashboards",
192-
render: pageProps => <DashboardListPage {...pageProps} currentPage="favorites" />,
199+
render: pageProps => <DashboardListPage {...pageProps} currentPage="favorites" orderByField="starred_at" />,
193200
})
194201
);
195202
routes.register(

client/app/pages/home/components/FavoritesList.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function FavoriteList({ title, resource, itemUrl, emptyState }) {
1515
useEffect(() => {
1616
setLoading(true);
1717
resource
18-
.favorites()
18+
.favorites({ order: "-starred_at" })
1919
.then(({ results }) => setItems(results))
2020
.finally(() => setLoading(false));
2121
}, [resource]);

client/app/pages/queries-list/QueriesList.jsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,19 @@ function QueriesList({ controller }) {
108108
};
109109
}, []);
110110

111+
let usedListColumns = listColumns;
112+
if (controller.params.currentPage === "favorites") {
113+
usedListColumns = [
114+
...usedListColumns,
115+
Columns.dateTime.sortable({ title: "Starred At", field: "starred_at", width: "1%" }),
116+
];
117+
}
111118
const {
112119
areExtraActionsAvailable,
113120
listColumns: tableColumns,
114121
Component: ExtraActionsComponent,
115122
selectedItems,
116-
} = useItemsListExtraActions(controller, listColumns, QueriesListExtraActions);
123+
} = useItemsListExtraActions(controller, usedListColumns, QueriesListExtraActions);
117124

118125
return (
119126
<div className="page-queries-list">
@@ -199,7 +206,7 @@ const QueriesListPage = itemsList(
199206
return item => new Query(item);
200207
},
201208
}),
202-
() => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true })
209+
({ ...props }) => new UrlStateStorage({ orderByField: props.orderByField ?? "created_at", orderByReverse: true })
203210
);
204211

205212
routes.register(
@@ -215,7 +222,7 @@ routes.register(
215222
routeWithUserSession({
216223
path: "/queries/favorites",
217224
title: "Favorite Queries",
218-
render: pageProps => <QueriesListPage {...pageProps} currentPage="favorites" />,
225+
render: pageProps => <QueriesListPage {...pageProps} currentPage="favorites" orderByField="starred_at" />,
219226
})
220227
);
221228
routes.register(

redash/handlers/dashboards.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"-name": "-lowercase_name",
2727
"created_at": "created_at",
2828
"-created_at": "-created_at",
29+
"starred_at": "favorites-created_at",
30+
"-starred_at": "-favorites-created_at",
2931
}
3032

3133
order_results = partial(_order_results, default_order="-created_at", allowed_orders=order_map)

redash/handlers/queries.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
"-executed_at": "-query_results-retrieved_at",
4545
"created_by": "users-name",
4646
"-created_by": "-users-name",
47+
"starred_at": "favorites-created_at",
48+
"-starred_at": "-favorites-created_at",
4749
}
4850

4951
order_results = partial(_order_results, default_order="-created_at", allowed_orders=order_map)

redash/models/__init__.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,15 +1145,19 @@ def all_tags(cls, org, user):
11451145
def favorites(cls, user, base_query=None):
11461146
if base_query is None:
11471147
base_query = cls.all(user.org, user.group_ids, user.id)
1148-
return base_query.join(
1149-
(
1150-
Favorite,
1151-
and_(
1152-
Favorite.object_type == "Dashboard",
1153-
Favorite.object_id == Dashboard.id,
1154-
),
1148+
return (
1149+
base_query.distinct(cls.lowercase_name, Dashboard.created_at, Dashboard.slug, Favorite.created_at)
1150+
.join(
1151+
(
1152+
Favorite,
1153+
and_(
1154+
Favorite.object_type == "Dashboard",
1155+
Favorite.object_id == Dashboard.id,
1156+
),
1157+
)
11551158
)
1156-
).filter(Favorite.user_id == user.id)
1159+
.filter(Favorite.user_id == user.id)
1160+
)
11571161

11581162
@classmethod
11591163
def by_user(cls, user):

redash/serializers/__init__.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,19 @@ def serialize(self):
8282
else:
8383
result = [serialize_query(query, **self.options) for query in self.object_or_list]
8484
if self.options.get("with_favorite_state", True):
85-
favorite_ids = models.Favorite.are_favorites(current_user.id, self.object_or_list)
85+
queries = list(self.object_or_list)
86+
favorites = models.Favorite.query.filter(
87+
models.Favorite.object_id.in_([o.id for o in queries]),
88+
models.Favorite.object_type == "Query",
89+
models.Favorite.user_id == current_user.id,
90+
)
91+
favorites_dict = {fav.object_id: fav for fav in favorites}
92+
8693
for query in result:
87-
query["is_favorite"] = query["id"] in favorite_ids
94+
favorite = favorites_dict.get(query["id"])
95+
query["is_favorite"] = favorite is not None
96+
if favorite:
97+
query["starred_at"] = favorite.created_at
8898

8999
return result
90100

@@ -263,9 +273,19 @@ def serialize(self):
263273
else:
264274
result = [serialize_dashboard(obj, **self.options) for obj in self.object_or_list]
265275
if self.options.get("with_favorite_state", True):
266-
favorite_ids = models.Favorite.are_favorites(current_user.id, self.object_or_list)
267-
for obj in result:
268-
obj["is_favorite"] = obj["id"] in favorite_ids
276+
dashboards = list(self.object_or_list)
277+
favorites = models.Favorite.query.filter(
278+
models.Favorite.object_id.in_([o.id for o in dashboards]),
279+
models.Favorite.object_type == "Dashboard",
280+
models.Favorite.user_id == current_user.id,
281+
)
282+
favorites_dict = {fav.object_id: fav for fav in favorites}
283+
284+
for query in result:
285+
favorite = favorites_dict.get(query["id"])
286+
query["is_favorite"] = favorite is not None
287+
if favorite:
288+
query["starred_at"] = favorite.created_at
269289

270290
return result
271291

0 commit comments

Comments
 (0)