Skip to content

Dashboard filter by creator#180147

Merged
Dosant merged 37 commits intoelastic:mainfrom
Dosant:d/2024-04-05-create-by-filter
Apr 30, 2024
Merged

Dashboard filter by creator#180147
Dosant merged 37 commits intoelastic:mainfrom
Dosant:d/2024-04-05-create-by-filter

Conversation

@Dosant
Copy link
Copy Markdown
Contributor

@Dosant Dosant commented Apr 5, 2024

Part of https://github.com/elastic/kibana-team/issues/769

Summary

This PR adds a "created by" filter to the dashboard listing page. We've added the created_by field recently here so only newly created by interactive users dashboards will be populated with created_by

Demo

Screenshot 2024-04-25 at 16 32 03 Screenshot 2024-04-25 at 16 32 11

Implementation notes

Suggesting users

We suggest only the users that have at least one dashboard. We do this by aggregating dashboard saved objects by created_by. Because we don't have server-side pagination or sorting yet, in this initial version, I decided to do this client-side to keep it as simple as possible for now.

Initially, I did this server-side inside a dashboard plugin as an internal API route. In the long term, this should probably be moved to content management in some form, but it is not clear how it should look yet. This is the commit where I reverted and moved it to client-side 06316ee

Clint side filtering

The user filter is simply a client-side filter because we anyway currently have an in-memory table with client-side sorting and pagination. There is no much practical value in server-side filter atm
The filter allows to filter-in by multiple users. It also allows to filter items without creators

created_by filter isn't part of the query string

I introduced a separate state for this filter, similar to tableSort and pagination. The reason why the created_by filter isn't a part of the searchQuery is because we use profile_id which looks ugly for the user, e.g. u_mGBROF_q5bmFCATLXAcCwKa0k8JvONAwSruelyKA5E_0 so we can't just add it to a user-facing search query like we do with tags. profile_id is the correct identified we should use, username might not be enough in some cases + username in cloud is unreadble account number. The best alternative could be email, but it isn't always available. This is why I decided to keep the created_by filter hidden from the user behind the user picker popover and not expose it to the search bar. The created_by filter is synced into the URL just like the rest of the table state.

No distinguishing the current user

There is no logic in place that somehow highlights or renames the current user in the filter. This can be added, but to limit the scope of the MVP I didn't do it.

User filter component

We use the UsersProfilePopover provided by the security team. We use it without any overrides, so the component decides how to show users in a popover. I noticed a small visual issue with an email truncation in a smaller popover. Might be worth a separate issue.

Testing

  1. Create multiple new users
  2. Login for each of them
  3. Created a dashboard for each of them
  4. Play with the filter

Next Steps

The next step would be to add a column with the user:

image (5)

Release notes

The dashboard listing page now allows filtering dashboards by creators for dashboards created after version 8.14

@Dosant
Copy link
Copy Markdown
Contributor Author

Dosant commented Apr 5, 2024

/ci

@Dosant Dosant changed the title wip create by filter [wip] Dashboard filter by creator Apr 5, 2024
@Dosant
Copy link
Copy Markdown
Contributor Author

Dosant commented Apr 5, 2024

/ci

@Dosant
Copy link
Copy Markdown
Contributor Author

Dosant commented Apr 5, 2024

/ci

@Dosant
Copy link
Copy Markdown
Contributor Author

Dosant commented Apr 9, 2024

/ci

@Dosant Dosant added the ci:cloud-deploy Create or update a Cloud deployment label Apr 9, 2024
@Dosant
Copy link
Copy Markdown
Contributor Author

Dosant commented Apr 9, 2024

/ci

@Dosant
Copy link
Copy Markdown
Contributor Author

Dosant commented Apr 22, 2024

/ci

Copy link
Copy Markdown
Contributor

@davismcphee davismcphee left a comment

Choose a reason for hiding this comment

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

Code-only review. kbn-content-management-utils changes LGTM 👍

@Heenawter Heenawter self-requested a review April 26, 2024 13:53
Copy link
Copy Markdown
Contributor

@Heenawter Heenawter left a comment

Choose a reason for hiding this comment

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

Code review + tested locally. It works great! Left two nits about the "No creators" filter, but nothing blocking 👍

I noticed a small visual issue with an email truncation in a smaller popover. Might be worth a separate issue.

I think it's worth creating a separate issue for the truncation issues:

Screenshot 2024-04-26 at 11 33 54 AM

This is why I decided to keep the created_by filter hidden from the user behind the user picker popover and not expose it to the search bar. The created_by filter is synced into the URL just like the rest of the table state.

I think this is reasonable! I'm not convinced that a URL-state filter is the right move here in the first place, so I think keeping it all client-side is ideal.

content={
<FormattedMessage
id="contentManagement.tableList.listing.userFilter.emptyMessageTooltip"
defaultMessage="Creators are assigned when dashboards are created, (for all dashboards created after version 8.14)."
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not sure if the comma is supposed to be there?

Suggested change
defaultMessage="Creators are assigned when dashboards are created, (for all dashboards created after version 8.14)."
defaultMessage="Creators are assigned when dashboards are created (for all dashboards created after version 8.14)."

cc @amyjtechwriter

Copy link
Copy Markdown
Contributor

@sebelga sebelga left a comment

Choose a reason for hiding this comment

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

Great job, tested locally and works as expected 🎉

Regarding the implementation I would change one thing though.
I would not add the bulkGetUserProfiles prop as we can already create that handler internally. Every consumer passes the CoreStart contract to the table context so we can already fetch the user profile (we need to extend the contract here https://github.com/elastic/kibana/blob/main/packages/content-management/table_list_view_table/src/services.tsx#L76).

What we probably will need are some options to disable the createdBy filter.

I see that we have initialFilter as a string.

We could maybe replace it with a filtersConfig prop?

interface FiltersConfig {
  initialValue?: string;
  createdByEnabled?: boolean; // default to false
}

Regarding tests, I think it would be good to add some component integration tests (inside the "__jest__" folder)

}

// keep the user if it's selected
if (selectedUsers.includes(user.uid)) return true;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we want that?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry maybe not clear what I meant. 😊 Don't we want to not show the selected users when searching?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think it is a better ux. We want to show the selected users while searching even if they don't match, so that the user can unselect without clearing the filter first.

Basically, selected should always stay in the list

@azasypkin
Copy link
Copy Markdown
Contributor

ACK: will review today (on behalf of the Kibana Platform Security)

@Dosant Dosant self-assigned this Apr 29, 2024
Copy link
Copy Markdown
Contributor

@azasypkin azasypkin left a comment

Choose a reason for hiding this comment

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

Looks good from the security perspective 👍 If you find yourself needing to add the bulkGetUserProfiles API tag in more features, please let us know.

key: userProfile.uid,
label: getUserDisplayName(userProfile.user),
data: userProfile,
'data-test-subj': `userProfileSelectableOption-${userProfile.user.username}`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

question: any reason we cannot use uid instead of username? I can imagine the case when username might not be unique (same username, different security realms, different uid's).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

it is a bit hacky, but this is what was more convenient in tests, since I know the username, but don't know the u_id of the current user. I guess I can make an API request to fetch it. but not sure it is worth it in this case

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

but not sure it is worth it in this case

It's likely not worth it if it's not trivial. I was just not sure what happens if we have duplicated test attributes in prod - I assume nothing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

nothing! happens relatively often

Comment on lines +24 to +47
export async function loginAsInteractiveUser({
getService,
}: Pick<FtrProviderContext, 'getService'>): Promise<{
Cookie: string;
}> {
const config = getService('config');
const supertest = getService('supertestWithoutAuth');

const username = config.get('servers.kibana.username');
const password = config.get('servers.kibana.password');
const response = await supertest
.post('/internal/security/login')
.set('kbn-xsrf', 'xxx')
.send({
providerType: 'basic',
providerName: 'basic',
currentURL: '/',
params: { username, password },
})
.expect(200);
const cookie = parseCookie(response.header['set-cookie'][0])!.cookieString();

return { Cookie: cookie };
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

note: not a blocker for this PR, obviously, but it'd be great if we can start embracing testing with non-admin/non-superuser users when possible 🙂 If you're up for it in this or the next PRs, here are the examples: https://github.com/elastic/kibana/blob/main/x-pack/test/security_api_integration/tests/user_profiles/suggest.ts#L17. I'm also happy to guide if you have any questions or issues with that.

Having said that, glad to see more functional and API integration tests with changes like that. Good job!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I'll take a look

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is this also prefered for functional tests?

Copy link
Copy Markdown
Contributor

@azasypkin azasypkin Apr 29, 2024

Choose a reason for hiding this comment

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

Yes, definitely. Ideally, relying on specially crafted roles should be our default choice everywhere. And if it's not easy for some reason, we (Kibana Platform Security and Kibana QA) should make it simpler. This would help us to see, use, and test Kibana how most of our users see and use it, and sometimes it's not that pretty because we don't care enough about people with limited privileges - security accessibility, so to say.

@Dosant Dosant requested a review from sebelga April 29, 2024 15:27
@Dosant
Copy link
Copy Markdown
Contributor Author

Dosant commented Apr 30, 2024

@elasticmachine merge upstream

Copy link
Copy Markdown
Contributor

@sebelga sebelga left a comment

Choose a reason for hiding this comment

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

LGTM! 👍 Thanks for addressing the changes

@kibana-ci
Copy link
Copy Markdown

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
dashboard 446 458 +12
eventAnnotationListing 509 520 +11
filesManagement 139 150 +11
graph 261 272 +11
maps 1166 1177 +11
visualizations 415 426 +11
total +67

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
@kbn/content-management-table-list-view-common 7 8 +1
@kbn/content-management-table-list-view-table 33 34 +1
@kbn/content-management-utils 125 126 +1
total +3

Async chunks

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

id before after diff
cases 475.9KB 476.1KB +191.0B
dashboard 397.1KB 407.1KB +10.0KB
eventAnnotationListing 198.5KB 208.4KB +9.8KB
filesManagement 90.5KB 100.3KB +9.8KB
graph 387.4KB 397.3KB +9.8KB
maps 2.9MB 3.0MB +9.9KB
security 574.6KB 574.8KB +191.0B
securitySolution 13.7MB 13.7MB +191.0B
visualizations 273.6KB 283.4KB +9.8KB
total +59.7KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
dashboard 37.0KB 37.1KB +67.0B
eventAnnotationListing 10.7KB 10.7KB +54.0B
graph 7.8KB 7.9KB +54.0B
maps 50.5KB 50.5KB +54.0B
visualizations 60.9KB 61.0KB +54.0B
total +283.0B
Unknown metric groups

API count

id before after diff
@kbn/content-management-table-list-view-common 7 8 +1
@kbn/content-management-table-list-view-table 50 51 +1
@kbn/content-management-utils 191 192 +1
@kbn/user-profile-components 80 81 +1
total +4

History

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

cc @Dosant

@Dosant Dosant merged commit f5d7eb6 into elastic:main Apr 30, 2024
@kibanamachine kibanamachine added v8.15.0 backport:skip This PR does not require backporting labels Apr 30, 2024
@Dosant Dosant added release_note:enhancement and removed release_note:feature Makes this part of the condensed release notes labels May 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:enhancement Team:SharedUX Platform AppEx-SharedUX (formerly Global Experience) t// v8.15.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants