Skip to content
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

Improve logic for dashboard duplication title computation #185056

Conversation

eokoneyo
Copy link
Contributor

@eokoneyo eokoneyo commented Jun 8, 2024

Summary

follow up to #184777 (comment)

Previously, if a user has cloned a dashboard N times, in the worst case that the next duplication attempt is initiated from the initial dashboard N network calls would be required to find a unique title for the next uniquely titled clone. This update short circuits that process by querying for the last created dashboard, getting it's duplicationId, increment it and proposing it as the next dashboard duplicate title, with this approach there's still a chance we might suggest a dashboard title that's been claimed if the user modifies the dashboard title to a higher duplication Id after creation, especially that we are querying for the last created and this is situation we can't correct for, the resolution for the appropriate title in that case would be on the user.

How to test

  • Create couple of duplicated dashboards, the titles should follow the normal increment progression ie. n+1
  • Create some that skip the expected pattern by any increment of choice, on attempting to duplicate this dashboard the suggested title should be previous + 1
  • Choose to duplicate any previously created dashboard the suggested title should be the increment of the last duplicated dashboard

Checklist

@eokoneyo eokoneyo added Team:Presentation Presentation Team for Dashboard, Input Controls, and Canvas release_note:skip Skip the PR/issue when compiling release notes Project:Dashboard Usability Related to the Dashboard Usability initiative labels Jun 8, 2024
@eokoneyo eokoneyo self-assigned this Jun 8, 2024
@eokoneyo eokoneyo requested a review from a team as a code owner June 8, 2024 00:53
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-presentation (Team:Presentation)

@eokoneyo eokoneyo force-pushed the chore/improve-dashboard-duplication-title-computation branch 4 times, most recently from e7270a6 to fe490a0 Compare June 11, 2024 08:05
Copy link
Contributor

@ThomThomson ThomThomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great so far! Especially nice to see the functional and jest test additions.

Left a few code quality nits and some other comments.


if (isMatchedResultInvalid) {
({ hits: searchMatchPageHits, pagination: searchMatchPaginationObject } =
await contentManagement.client.search<
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why exactly do we need to run the search again? Or use a cursor? It seems to me this could work quite well with one search of ~20 or so Dashboards with no cursor where we simply loop through the results to find the highest number and increment that.

If we miss and accidentally return a number that isn't unique, nothing really breaks, the user just has to increment it themselves.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before switching the previous implementation, I'd used a cursor so we are able to fetch the last page of the search so we can pick the last created dashboard without having to loop multiple times. I opted for this approach because if we have a situation where the duplicated dashboard count exceeds search limit (right now it's 10) the returned page would not give us a way to determine the highest number without performing multiple loops.

I have switched the implementation though now so we are able to sort and simply pick the the last incremented dashboard.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's okay. If the user has more than 10 Dashboards with the same basic title structure, it's completely okay if this doesn't recommend a unique title in ~5% or less of cases. Remember that the behaviour we're replacing simply told the user their title wasn't unique and let them figure out how to make it unique.

@eokoneyo eokoneyo force-pushed the chore/improve-dashboard-duplication-title-computation branch from 75676e8 to 6b7bb62 Compare June 12, 2024 18:12
Comment on lines 39 to 50
export const dashboardSearchOptionsSchema = dashboardSearchOptionsSchemaV1.extends(
{
sort: schema.maybe(
schema.object({
sortField: searchOptionsSchemas.sortField,
sortOrder: searchOptionsSchemas.sortOrder,
})
),
},
{ unknowns: 'ignore' }
);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added this search option in V2, as it's a backward compatible change and also opt-in I'm not sure if this warrants a V3

Comment on lines 281 to 301
const [baseTitle] = extractTitleAndCount(newTitle);

const { hits: recentlyCreatedDashboards } = await findDashboards.search({
size: 1,
search: baseTitle,
options: {
onlyTitle: true,
sort: {
sortField: 'created_at',
sortOrder: 'desc',
},
},
});

const [, mostRecentDuplicationId] = extractTitleAndCount(
recentlyCreatedDashboards[0].attributes.title
);

let copyCount = mostRecentDuplicationId + 1;

newTitle = `${baseTitle} (${copyCount})`;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request the last created dashboard, and use it's duplication Id to create the proposed duplicate title.

@eokoneyo eokoneyo force-pushed the chore/improve-dashboard-duplication-title-computation branch 2 times, most recently from a7444cd to e5b8ce2 Compare June 13, 2024 09:49
@eokoneyo eokoneyo force-pushed the chore/improve-dashboard-duplication-title-computation branch from e5b8ce2 to c5ba26c Compare June 13, 2024 09:55
Copy link
Contributor

@ThomThomson ThomThomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this PR again, it seems like we're adding a lot of difficult to maintain code for very dubious user benefit.

All we're doing here is recommending a new title that might be unique. The consequences of accidentally returning a title that isn't unique are very low stakes. In that case the user just needs to write a unique title themselves. That tells me that this code does not need to work perfectly and a "good enough" approach is warranted.

I'd recommend removing almost all of the complexity here - especially the changes to the schema and content management, and building this functionality to cover 90% of the ways it will be used (duplicating a Dashboard once or twice).

@cqliu1
Copy link
Contributor

cqliu1 commented Jun 17, 2024

@ThomThomson I'm taking over this PR while Eyo's out. I've removed all of the content management changes and simplified the logic for the duplicate title check. Only one dashboard search request is fired when the save modal renders to generate a best attempt at a unique title. It reliably finds a unique title until you have 20+ copies of the same dashboard with the same base title, and only struggles to find a unique title suggestion if you're duplicating one of the older duplicates with a lower count. It should still consistently suggest a unique title when duplicating one of the newer duplicate dashboards with a higher count. This should sufficiently cover most of the scenarios a user will run into.

Copy link
Contributor

@ThomThomson ThomThomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes LGTM! Tested locally in chrome, and it's working great. Left a few nits

@@ -30,6 +35,7 @@ export async function checkForDuplicateDashboardTitle(
lastSavedTitle,
onTitleDuplicate,
isTitleDuplicateConfirmed,
searchLimit = 20,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to be an argument? It seems like it can just be hardcoded in the function more simply.

const { hits } = await contentManagement.client.search<
DashboardCrudTypes['SearchIn'],
DashboardCrudTypes['SearchOut']
>({
contentTypeId: DASHBOARD_CONTENT_ID,
query: {
text: title ? `${title}*` : undefined,
limit: 10,
text: title ? `${baseDashboardName}*` : undefined,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of falling back to undefined here, can we just cancel the whole operation if the title is undefined?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be undefined, but it's possible to receive an empty string. We can certainly return early and skip the whole check.

limit: 10,
text: title ? `${baseDashboardName}*` : undefined,
limit: searchLimit,
cursor: String(duplicationId ? Math.ceil(duplicationId / searchLimit) : 1),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a cursor still?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily. Setting the cursor is only useful if there are more than the 20 duplicate dashboards, but even without this, we'll still come up with a good enough suggestion.

@@ -49,5 +49,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await PageObjects.dashboard.gotoDashboardLandingPage();
await listingTable.searchAndExpectItemsCount('dashboard', `${dashboardName} (2)`, 1);
});

it('Clone should always increment from the last duplicated dashboard with a unique title', async function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding a functional test!

@cqliu1 cqliu1 enabled auto-merge (squash) June 18, 2024 01:16
@kibana-ci
Copy link
Collaborator

💛 Build succeeded, but was flaky

Failed CI Steps

Metrics [docs]

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
dashboard 489.3KB 489.6KB +310.0B

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @eokoneyo

@cqliu1 cqliu1 merged commit 641a71b into elastic:main Jun 18, 2024
26 checks passed
@kibanamachine kibanamachine added v8.15.0 backport:skip This commit does not require backporting labels Jun 18, 2024
bhapas pushed a commit to bhapas/kibana that referenced this pull request Jun 18, 2024
…5056)

## Summary

follow up to
elastic#184777 (comment)

Previously, if a user has cloned a dashboard N times, in the worst case
that the next duplication attempt is initiated from the initial
dashboard N network calls would be required to find a unique title for
the next uniquely titled clone. This update short circuits that process
by querying for the last created dashboard, getting it's duplicationId,
increment it and proposing it as the next dashboard duplicate title,
with this approach there's still a chance we might suggest a dashboard
title that's been claimed if the user modifies the dashboard title to a
higher duplication Id after creation, especially that we are querying
for the last created and this is situation we can't correct for, the
resolution for the appropriate title in that case would be on the user.

## How to test
- Create couple of duplicated dashboards, the titles should follow the
normal increment progression ie. n+1
- Create some that skip the expected pattern by any increment of choice,
on attempting to duplicate this dashboard the suggested title should be
previous + 1
- Choose to duplicate any previously created dashboard the suggested
title should be the increment of the last duplicated dashboard


### Checklist


<!-- Delete any items that are not applicable to this PR. -->

<!--
- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials -->
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
<!-- 
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [ ] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [ ] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)


### Risk Matrix

Delete this section if it is not applicable to this PR.

Before closing this PR, invite QA, stakeholders, and other developers to
identify risks that should be tested prior to the change/feature
release.

When forming the risk matrix, consider some of the following examples
and how they may potentially impact the change:

| Risk | Probability | Severity | Mitigation/Notes |

|---------------------------|-------------|----------|-------------------------|
| Multiple Spaces&mdash;unexpected behavior in non-default Kibana Space.
| Low | High | Integration tests will verify that all features are still
supported in non-default Kibana Space and when user switches between
spaces. |
| Multiple nodes&mdash;Elasticsearch polling might have race conditions
when multiple Kibana nodes are polling for the same tasks. | High | Low
| Tasks are idempotent, so executing them multiple times will not result
in logical error, but will degrade performance. To test for this case we
add plenty of unit tests around this logic and document manual testing
procedure. |
| Code should gracefully handle cases when feature X or plugin Y are
disabled. | Medium | High | Unit tests will verify that any feature flag
or plugin combination still results in our service operational. |
| [See more potential risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) |


### For maintainers

- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
-->

---------

Co-authored-by: Catherine Liu <catherine.liu@elastic.co>
@eokoneyo eokoneyo deleted the chore/improve-dashboard-duplication-title-computation branch July 1, 2024 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting Project:Dashboard Usability Related to the Dashboard Usability initiative release_note:skip Skip the PR/issue when compiling release notes Team:Presentation Presentation Team for Dashboard, Input Controls, and Canvas v8.15.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants