[Dashboards] Register dashboard locator on server start#218495
[Dashboards] Register dashboard locator on server start#218495nickpeihl merged 15 commits intoelastic:mainfrom
Conversation
| new DashboardAppLocatorDefinition({ | ||
| useHashedUrl: false, | ||
| getDashboardFilterFields: async (dashboardId: string) => { | ||
| return []; |
There was a problem hiding this comment.
If we want to get the filters from a saved dashboard in the same way we do on the client-side then we'll somehow need to include the RequestHandlerContext so we can scope the content management client to the current user.
Similar to the useHashedUrls example above, we need to use the ctx argument to create a content management client scoped to the user to pass to the locator.
// in src/platform/plugins/shared/share/server/url_service/http/short_urls/register_create_route.ts
export const registerCreateRoute = (router: IRouter, url: ServerUrlService, contentManagement: ContentManagementServerSetup) => {
...
router.handleLegacyErrors(async (ctx, req, res) => {
const savedObjects = (await ctx.core).savedObjects.client;
const cmClient = contentManagement.contentClient
.getForRequest({ request: req, requestHandlerContext: ctx })
const shortUrls = url.shortUrls.get({ savedObjects });
const { locatorId, params, slug } = req.body;
const locator = url.locators.get(locatorId);
// TODO find a way to pass cmClient to the locator. Maybe in params?
try {
const shortUrl = await shortUrls.create({
locator,
params,
slug,
});
return res.ok({
headers: {
'content-type': 'application/json',
},
body: shortUrl.data,
});
} catch (error) {There was a problem hiding this comment.
AFAICT, the getLocation method from the LocatorPublic interface is never actually called by the server. So, it currently does not matter on the Dashboard server contract what we set for useHashedUrls or the return value of getDashboardFilterFields because, currently, they are never be used by Kibana server. It seems that the getLocation is only currently ever used by the client.
Also, the URLService on the Share server plugin only exposes certain locator methods but they are not supported on the server. So I suspect we can safely assume the getLocation is not directly exposed on the server side URL service and it will likely not get called from the server. Maybe someone from @elastic/appex-sharedux can keep me honest here?
So I think we have two options for registering the Dashboard locator on the server:
- Have
getDashboardFilterFieldsalways return an empty array. Currently, this function is never called. But any future implementations wheregetLocationis called on the server would not retrieve any saved filters on a dashboard. So it would not break, but might return unexpected results. - Have
getDashboardFilterFieldsthrow an error as not supported on the server. Again, this should currently never throw sincegetLocationis not called by the server. But any future implementations wheregetLocationis called on the server would throw an error. cc @ThomThomson
There was a problem hiding this comment.
Good find! That will definitely make this simpler. I'd suggest making it throw an error on the serverside - which will make sure we revisit this if we ever need to call getLocation on the server.
| if (plugins.share) { | ||
| plugins.share.url.locators.create( | ||
| new DashboardAppLocatorDefinition({ | ||
| useHashedUrl: false, |
There was a problem hiding this comment.
If we want to support hashed urls on the server the same way we do on the client-side, we'll need the RequestHandlerContext) so we can scope the server-side UISettingsServiceStart.asScopedToClient to retrieve the 'state:storeInSessionStorage' setting as we do in the client.
For example: The short URL create route passes the ctx: RequestHandlerContext. We use this to scope the savedObjects client to the user making the request. To retrieve the 'state:storeInSessionStorage' setting we need to do something like this:
// in src/platform/plugins/shared/share/server/url_service/http/short_urls/register_create_route.ts
router.handleLegacyErrors(async (ctx, req, res) => {
const savedObjects = (await ctx.core).savedObjects.client;
const uiSettingsClient = core.uiSettings.asScopedToClient(soClient);
const useHashedUrl = uiSettingsClient.get('state:storeInSessionStorage');
const shortUrls = url.shortUrls.get({ savedObjects });
const { locatorId, params, slug } = req.body;
const locator = url.locators.get(locatorId);
// TODO find a way to pass useHashedUrl to the locator. Maybe in params?
try {
const shortUrl = await shortUrls.create({
locator,
params,
slug,
});
return res.ok({
headers: {
'content-type': 'application/json',
},
body: shortUrl.data,
});
} catch (error) {FWIW, the server-side Discover locator does not support hashed URLs.
There was a problem hiding this comment.
I'd say it's safe to not support hashing on the serverside locator for Dashboards.
|
Pinging @elastic/kibana-presentation (Team:Presentation) |
|
|
||
| export const UI_SETTINGS = { | ||
| ENABLE_LABS_UI: 'labs:dashboard:enable_ui', | ||
| }; |
There was a problem hiding this comment.
These top level exports were removed to avoid bloating the bundle size. Aside from types, the imports from common in dashboard/public have been changed to deep imports.
rmyz
left a comment
There was a problem hiding this comment.
x-pack/solutions/observability/plugins/inventory/public/hooks/use_detail_view_redirect.ts changes LGTM
ThomThomson
left a comment
There was a problem hiding this comment.
Changes LGTM! Mostly import changes, code only review.
| new DashboardAppLocatorDefinition({ | ||
| useHashedUrl: false, | ||
| getDashboardFilterFields: async (dashboardId: string) => { | ||
| throw new Error( |
There was a problem hiding this comment.
Thanks for throwing an error here!
|
Removed Operations as we no longer have code owner changes in this PR. |
|
Starting backport for target branches: 8.19 https://github.com/elastic/kibana/actions/runs/14711519816 |
💚 Build Succeeded
Metrics [docs]Public APIs missing comments
Async chunks
Public APIs missing exports
Page load bundle
History
|
💔 All backports failed
Manual backportTo create the backport manually run: Questions ?Please refer to the Backport tool documentation |
💚 All backports created successfully
Note: Successful backport PRs will be merged automatically after passing CI. Questions ?Please refer to the Backport tool documentation |
## Summary
Registers the dashboard locator definition with the share plugin on the
Dashboard server start contract.
This moves Dashboard locator code from public to common so that we can
expose the Dashboard Locator definition on the server. The `getLocation`
method exposed by the locator does not appear to be used by any server
code. So the `getDashboardFilterFields` function provided to the
`DashboardLocatorDefinition` will throw a not supported error on the
server. This should currently never throw since getLocation is not
called by the server. But any future implementations where getLocation
is called on the server would throw an error and thus would need to
augment this function.
For posterity, here's an example where, in the future, we might need to
provide a scoped content management client to the DashboardLocatorParams
that can be used to load filters from a saved dashboard in the
`getDashboardFilterFields` function.
```ts
// in src/platform/plugins/shared/share/server/url_service/http/short_urls/register_create_route.ts
export const registerCreateRoute = (router: IRouter, url: ServerUrlService, contentManagement: ContentManagementServerSetup) => {
router.handleLegacyErrors(async (ctx, req, res) => {
const savedObjects = (await ctx.core).savedObjects.client;
const cmClient = contentManagement.contentClient
.getForRequest({ request: req, requestHandlerContext: ctx })
const shortUrls = url.shortUrls.get({ savedObjects });
const { locatorId, params, slug } = req.body;
const locator = url.locators.get(locatorId);
// TODO find a way to pass cmClient to the locator. Maybe in params?
try {
const shortUrl = await shortUrls.create({
locator,
params,
slug,
});
return res.ok({
headers: {
'content-type': 'application/json',
},
body: shortUrl.data,
});
} catch (error) {
```
(cherry picked from commit 8e1a426)
# Conflicts:
# src/platform/plugins/shared/dashboard/public/dashboard_top_nav/dashboard_favorite_button.tsx
# x-pack/platform/plugins/shared/ml/public/application/jobs/new_job/job_from_dashboard/quick_create_job_base.ts
…) (#219717) # Backport This will backport the following commits from `main` to `8.19`: - [[Dashboards] Register dashboard locator on server start (#218495)](#218495) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Nick Peihl","email":"nick.peihl@elastic.co"},"sourceCommit":{"committedDate":"2025-04-28T15:23:18Z","message":"[Dashboards] Register dashboard locator on server start (#218495)\n\n## Summary\n\nRegisters the dashboard locator definition with the share plugin on the\nDashboard server start contract.\n\nThis moves Dashboard locator code from public to common so that we can\nexpose the Dashboard Locator definition on the server. The `getLocation`\nmethod exposed by the locator does not appear to be used by any server\ncode. So the `getDashboardFilterFields` function provided to the\n`DashboardLocatorDefinition` will throw a not supported error on the\nserver. This should currently never throw since getLocation is not\ncalled by the server. But any future implementations where getLocation\nis called on the server would throw an error and thus would need to\naugment this function.\n\nFor posterity, here's an example where, in the future, we might need to\nprovide a scoped content management client to the DashboardLocatorParams\nthat can be used to load filters from a saved dashboard in the\n`getDashboardFilterFields` function.\n\n```ts\n// in src/platform/plugins/shared/share/server/url_service/http/short_urls/register_create_route.ts\n\nexport const registerCreateRoute = (router: IRouter, url: ServerUrlService, contentManagement: ContentManagementServerSetup) => {\n\nrouter.handleLegacyErrors(async (ctx, req, res) => {\n const savedObjects = (await ctx.core).savedObjects.client;\n\n const cmClient = contentManagement.contentClient\n .getForRequest({ request: req, requestHandlerContext: ctx })\n\n const shortUrls = url.shortUrls.get({ savedObjects });\n const { locatorId, params, slug } = req.body;\n const locator = url.locators.get(locatorId);\n // TODO find a way to pass cmClient to the locator. Maybe in params?\n \n try {\n const shortUrl = await shortUrls.create({\n locator,\n params,\n slug,\n });\n\n return res.ok({\n headers: {\n 'content-type': 'application/json',\n },\n body: shortUrl.data,\n });\n} catch (error) {\n```","sha":"8e1a426c25497f332fd516dee46061c900618e96","branchLabelMapping":{"^v9.1.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Presentation","release_note:skip","Feature:Drilldowns","backport:version","v9.1.0","v8.19.0"],"title":"[Dashboards] Register dashboard locator on server start","number":218495,"url":"https://github.com/elastic/kibana/pull/218495","mergeCommit":{"message":"[Dashboards] Register dashboard locator on server start (#218495)\n\n## Summary\n\nRegisters the dashboard locator definition with the share plugin on the\nDashboard server start contract.\n\nThis moves Dashboard locator code from public to common so that we can\nexpose the Dashboard Locator definition on the server. The `getLocation`\nmethod exposed by the locator does not appear to be used by any server\ncode. So the `getDashboardFilterFields` function provided to the\n`DashboardLocatorDefinition` will throw a not supported error on the\nserver. This should currently never throw since getLocation is not\ncalled by the server. But any future implementations where getLocation\nis called on the server would throw an error and thus would need to\naugment this function.\n\nFor posterity, here's an example where, in the future, we might need to\nprovide a scoped content management client to the DashboardLocatorParams\nthat can be used to load filters from a saved dashboard in the\n`getDashboardFilterFields` function.\n\n```ts\n// in src/platform/plugins/shared/share/server/url_service/http/short_urls/register_create_route.ts\n\nexport const registerCreateRoute = (router: IRouter, url: ServerUrlService, contentManagement: ContentManagementServerSetup) => {\n\nrouter.handleLegacyErrors(async (ctx, req, res) => {\n const savedObjects = (await ctx.core).savedObjects.client;\n\n const cmClient = contentManagement.contentClient\n .getForRequest({ request: req, requestHandlerContext: ctx })\n\n const shortUrls = url.shortUrls.get({ savedObjects });\n const { locatorId, params, slug } = req.body;\n const locator = url.locators.get(locatorId);\n // TODO find a way to pass cmClient to the locator. Maybe in params?\n \n try {\n const shortUrl = await shortUrls.create({\n locator,\n params,\n slug,\n });\n\n return res.ok({\n headers: {\n 'content-type': 'application/json',\n },\n body: shortUrl.data,\n });\n} catch (error) {\n```","sha":"8e1a426c25497f332fd516dee46061c900618e96"}},"sourceBranch":"main","suggestedTargetBranches":["8.19"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/218495","number":218495,"mergeCommit":{"message":"[Dashboards] Register dashboard locator on server start (#218495)\n\n## Summary\n\nRegisters the dashboard locator definition with the share plugin on the\nDashboard server start contract.\n\nThis moves Dashboard locator code from public to common so that we can\nexpose the Dashboard Locator definition on the server. The `getLocation`\nmethod exposed by the locator does not appear to be used by any server\ncode. So the `getDashboardFilterFields` function provided to the\n`DashboardLocatorDefinition` will throw a not supported error on the\nserver. This should currently never throw since getLocation is not\ncalled by the server. But any future implementations where getLocation\nis called on the server would throw an error and thus would need to\naugment this function.\n\nFor posterity, here's an example where, in the future, we might need to\nprovide a scoped content management client to the DashboardLocatorParams\nthat can be used to load filters from a saved dashboard in the\n`getDashboardFilterFields` function.\n\n```ts\n// in src/platform/plugins/shared/share/server/url_service/http/short_urls/register_create_route.ts\n\nexport const registerCreateRoute = (router: IRouter, url: ServerUrlService, contentManagement: ContentManagementServerSetup) => {\n\nrouter.handleLegacyErrors(async (ctx, req, res) => {\n const savedObjects = (await ctx.core).savedObjects.client;\n\n const cmClient = contentManagement.contentClient\n .getForRequest({ request: req, requestHandlerContext: ctx })\n\n const shortUrls = url.shortUrls.get({ savedObjects });\n const { locatorId, params, slug } = req.body;\n const locator = url.locators.get(locatorId);\n // TODO find a way to pass cmClient to the locator. Maybe in params?\n \n try {\n const shortUrl = await shortUrls.create({\n locator,\n params,\n slug,\n });\n\n return res.ok({\n headers: {\n 'content-type': 'application/json',\n },\n body: shortUrl.data,\n });\n} catch (error) {\n```","sha":"8e1a426c25497f332fd516dee46061c900618e96"}},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
## Summary
Registers the dashboard locator definition with the share plugin on the
Dashboard server start contract.
This moves Dashboard locator code from public to common so that we can
expose the Dashboard Locator definition on the server. The `getLocation`
method exposed by the locator does not appear to be used by any server
code. So the `getDashboardFilterFields` function provided to the
`DashboardLocatorDefinition` will throw a not supported error on the
server. This should currently never throw since getLocation is not
called by the server. But any future implementations where getLocation
is called on the server would throw an error and thus would need to
augment this function.
For posterity, here's an example where, in the future, we might need to
provide a scoped content management client to the DashboardLocatorParams
that can be used to load filters from a saved dashboard in the
`getDashboardFilterFields` function.
```ts
// in src/platform/plugins/shared/share/server/url_service/http/short_urls/register_create_route.ts
export const registerCreateRoute = (router: IRouter, url: ServerUrlService, contentManagement: ContentManagementServerSetup) => {
router.handleLegacyErrors(async (ctx, req, res) => {
const savedObjects = (await ctx.core).savedObjects.client;
const cmClient = contentManagement.contentClient
.getForRequest({ request: req, requestHandlerContext: ctx })
const shortUrls = url.shortUrls.get({ savedObjects });
const { locatorId, params, slug } = req.body;
const locator = url.locators.get(locatorId);
// TODO find a way to pass cmClient to the locator. Maybe in params?
try {
const shortUrl = await shortUrls.create({
locator,
params,
slug,
});
return res.ok({
headers: {
'content-type': 'application/json',
},
body: shortUrl.data,
});
} catch (error) {
```
Summary
Registers the dashboard locator definition with the share plugin on the Dashboard server start contract.
This moves Dashboard locator code from public to common so that we can expose the Dashboard Locator definition on the server. The
getLocationmethod exposed by the locator does not appear to be used by any server code. So thegetDashboardFilterFieldsfunction provided to theDashboardLocatorDefinitionwill throw a not supported error on the server. This should currently never throw since getLocation is not called by the server. But any future implementations where getLocation is called on the server would throw an error and thus would need to augment this function.For posterity, here's an example where, in the future, we might need to provide a scoped content management client to the DashboardLocatorParams that can be used to load filters from a saved dashboard in the
getDashboardFilterFieldsfunction.