-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Dashboard URL does not show new name when dashboard name is updated #1009
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 18 commits
467a128
1e818f6
90ef7cc
8392126
aba6e3b
0ae13b0
0783351
1aedc44
b7a7a55
a851402
75b71d7
6ea5b97
8e5f491
3f47fb8
2649292
59a9143
169200e
1c9bbbe
2cf590b
49482d9
52041a3
2ccc4c1
08c14de
d7728d1
d166069
210a755
7a8cb0e
0957129
eb82583
fd26a9f
6e68b91
2de74b3
cd867a7
212d4b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -144,36 +144,48 @@ DashboardComponent.propTypes = { | |
| dashboard: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types | ||
| }; | ||
|
|
||
| function DashboardPage({ dashboardSlug, onError }) { | ||
| function DashboardPage({ dashboardSlug, dashboardId, onError }) { | ||
| const [dashboard, setDashboard] = useState(null); | ||
| const onErrorRef = useRef(); | ||
| onErrorRef.current = onError; | ||
|
|
||
| useEffect(() => { | ||
| Dashboard.get({ slug: dashboardSlug }) | ||
| Dashboard.get({ id: dashboardId, slug: dashboardSlug }) | ||
| .then(dashboardData => { | ||
| recordEvent("view", "dashboard", dashboardData.id); | ||
| setDashboard(dashboardData); | ||
| }) | ||
| .catch(error => onErrorRef.current(error)); | ||
| }, [dashboardSlug]); | ||
| }, [dashboardSlug, dashboardId]); | ||
|
|
||
| return <div className="dashboard-page">{dashboard && <DashboardComponent dashboard={dashboard} />}</div>; | ||
| } | ||
|
|
||
| DashboardPage.propTypes = { | ||
| dashboardSlug: PropTypes.string.isRequired, | ||
| dashboardSlug: PropTypes.string, | ||
| dashboardId: PropTypes.string, | ||
| onError: PropTypes.func, | ||
| }; | ||
|
|
||
| DashboardPage.defaultProps = { | ||
| dashboardSlug: null, | ||
| dashboardId: null, | ||
| onError: PropTypes.func, | ||
| }; | ||
|
|
||
| // route kept for backward compatibility | ||
| routes.register( | ||
| "Dashboards.ViewOrEdit", | ||
gabrieldutra marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| routeWithUserSession({ | ||
| path: "/dashboard/:dashboardSlug", | ||
| render: pageProps => <DashboardPage {...pageProps} />, | ||
| }) | ||
arikfr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ); | ||
|
|
||
| routes.register( | ||
| "Dashboards.ViewOrEditWithId", | ||
gabrieldutra marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| routeWithUserSession({ | ||
| path: "/dashboards/:dashboardId-(.*)?", | ||
|
||
| render: pageProps => <DashboardPage {...pageProps} />, | ||
| }) | ||
| ); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ import { useState, useEffect, useMemo, useCallback, useRef } from "react"; | |
| import { isEmpty, includes, compact, map, has, pick, keys, extend, every, get } from "lodash"; | ||
| import notification from "@/services/notification"; | ||
| import location from "@/services/location"; | ||
| import { Dashboard, collectDashboardFilters } from "@/services/dashboard"; | ||
| import { Dashboard, collectDashboardFilters, urlForDashboard } from "@/services/dashboard"; | ||
| import { currentUser } from "@/services/auth"; | ||
| import recordEvent from "@/services/recordEvent"; | ||
| import { QueryResultError } from "@/services/query"; | ||
|
|
@@ -14,6 +14,7 @@ import ShareDashboardDialog from "../components/ShareDashboardDialog"; | |
| import useFullscreenHandler from "../../../lib/hooks/useFullscreenHandler"; | ||
| import useRefreshRateHandler from "./useRefreshRateHandler"; | ||
| import useEditModeHandler from "./useEditModeHandler"; | ||
| import navigateTo from "@/components/ApplicationArea/navigateTo"; | ||
|
|
||
| export { DashboardStatusEnum } from "./useEditModeHandler"; | ||
|
|
||
|
|
@@ -69,9 +70,12 @@ function useDashboard(dashboardData) { | |
| data = { ...data, version: dashboard.version }; | ||
| } | ||
| return Dashboard.save(data) | ||
| .then(updatedDashboard => | ||
| setDashboard(currentDashboard => extend({}, currentDashboard, pick(updatedDashboard, keys(data)))) | ||
| ) | ||
| .then(updatedDashboard => { | ||
| setDashboard(currentDashboard => extend({}, currentDashboard, pick(updatedDashboard, keys(data)))); | ||
| if (has(data, "name")) { | ||
| navigateTo(urlForDashboard(updatedDashboard), true); | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, correct |
||
| }) | ||
| .catch(error => { | ||
| const status = get(error, "response.status"); | ||
| if (status === 403) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -150,7 +150,7 @@ def get(self, dashboard_slug=None): | |
| :>json string widget.updated_at: ISO format timestamp for last widget modification | ||
| """ | ||
| dashboard = get_object_or_404( | ||
| models.Dashboard.get_by_slug_and_org, dashboard_slug, self.current_org | ||
| models.Dashboard.get_by_id_or_slug_and_org, dashboard_slug, self.current_org | ||
|
||
| ) | ||
| response = DashboardSerializer( | ||
| dashboard, with_widgets=True, user=self.current_user | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,7 @@ | |
| import numbers | ||
| import pytz | ||
|
|
||
| from sqlalchemy import distinct, or_, and_, UniqueConstraint | ||
| from sqlalchemy import distinct, or_, and_, UniqueConstraint, cast | ||
| from sqlalchemy.dialects import postgresql | ||
| from sqlalchemy.event import listens_for | ||
| from sqlalchemy.ext.hybrid import hybrid_property | ||
|
|
@@ -1097,6 +1097,10 @@ class Dashboard(ChangeTrackingMixin, TimestampMixin, BelongsToOrgMixin, db.Model | |
| def __str__(self): | ||
| return "%s=%s" % (self.id, self.name) | ||
|
|
||
| @property | ||
| def name_as_slug(self): | ||
| return utils.slugify(self.name) | ||
|
|
||
| @classmethod | ||
| def all(cls, org, group_ids, user_id): | ||
| query = ( | ||
|
|
@@ -1168,6 +1172,15 @@ def favorites(cls, user, base_query=None): | |
| def get_by_slug_and_org(cls, slug, org): | ||
| return cls.query.filter(cls.slug == slug, cls.org == org).one() | ||
|
|
||
| @classmethod | ||
| def get_by_id_or_slug_and_org(cls, id_or_slug, org): | ||
| return ( | ||
| cls.query.filter( | ||
| cast(cls.id, db.String) == id_or_slug, cls.org == org | ||
| ).one_or_none() | ||
| or cls.query.filter(cls.slug == id_or_slug, cls.org == org).one() | ||
|
||
| ) | ||
|
|
||
| @hybrid_property | ||
| def lowercase_name(self): | ||
| "Optional property useful for sorting purposes." | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -246,6 +246,7 @@ def serialize_dashboard(obj, with_widgets=False, user=None, with_favorite_state= | |
| d = { | ||
| "id": obj.id, | ||
| "slug": obj.slug, | ||
| "name_as_slug": obj.name_as_slug, | ||
|
||
| "name": obj.name, | ||
| "user_id": obj.user_id, | ||
| "user": { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about we transform the response we receive and add a URL field to it, so we don't have to import (or remember to use)
urlForDashboardeverywhere?