Skip to content

Commit

Permalink
feat(settings): show last login timestamp for team members (#25006)
Browse files Browse the repository at this point in the history
  • Loading branch information
abhi12299 authored Sep 20, 2024
1 parent 47b7d6d commit b113f11
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 1 deletion.
2 changes: 2 additions & 0 deletions frontend/src/lib/api.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export const MOCK_DEFAULT_ORGANIZATION_MEMBER: OrganizationMemberType = {
updated_at: '2020-09-24T15:05:26.758837Z',
is_2fa_enabled: false,
has_social_auth: false,
last_login: '2020-09-24T15:05:26.758796Z',
}

export const MOCK_SECOND_BASIC_USER: UserBasicType = {
Expand All @@ -181,6 +182,7 @@ export const MOCK_SECOND_ORGANIZATION_MEMBER: OrganizationMemberType = {
updated_at: '2021-03-11T19:11:11Z',
is_2fa_enabled: false,
has_social_auth: false,
last_login: '2020-09-24T15:05:26.758796Z',
}

export const MOCK_DEFAULT_ORGANIZATION_INVITE: OrganizationInviteType = {
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/scenes/settings/organization/Members.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,19 @@ export function Members(): JSX.Element | null {
},
sorter: (a, b) => a.joined_at.localeCompare(b.joined_at),
},
{
title: 'Last Logged In',
dataIndex: 'last_login',
key: 'last_login',
render: function RenderLastLogin(lastLogin) {
return (
<div className="whitespace-nowrap">
{lastLogin ? <TZLabel time={lastLogin as string} /> : 'Never'}
</div>
)
},
sorter: (a, b) => new Date(a.last_login ?? 0).getTime() - new Date(b.last_login ?? 0).getTime(),
},
{
key: 'actions',
width: 0,
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ export interface OrganizationDomainType {
export interface BaseMemberType {
id: string
user: UserBasicType
last_login: string | null
joined_at: string
updated_at: string
is_2fa_enabled: boolean
Expand Down
5 changes: 4 additions & 1 deletion posthog/api/organization_member.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import cast

from django.db.models import Model, Prefetch, QuerySet
from django.db.models import Model, Prefetch, QuerySet, F
from django.shortcuts import get_object_or_404
from django.views import View
from django_otp.plugins.otp_totp.models import TOTPDevice
Expand Down Expand Up @@ -42,6 +42,7 @@ class OrganizationMemberSerializer(serializers.ModelSerializer):
user = UserBasicSerializer(read_only=True)
is_2fa_enabled = serializers.SerializerMethodField()
has_social_auth = serializers.SerializerMethodField()
last_login = serializers.DateTimeField(read_only=True)

class Meta:
model = OrganizationMembership
Expand All @@ -53,6 +54,7 @@ class Meta:
"updated_at",
"is_2fa_enabled",
"has_social_auth",
"last_login",
]
read_only_fields = ["id", "joined_at", "updated_at"]

Expand Down Expand Up @@ -107,6 +109,7 @@ class OrganizationMemberViewSet(
),
Prefetch("user__social_auth", queryset=UserSocialAuth.objects.all()),
)
.annotate(last_login=F("user__last_login"))
)
lookup_field = "user__uuid"

Expand Down
1 change: 1 addition & 0 deletions posthog/api/test/test_organization_members.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def test_change_organization_member_level(self, mock_update_billing_organization
response_data = response.json()
response_data.pop("joined_at")
response_data.pop("updated_at")
response_data.pop("last_login")
self.assertDictEqual(
response_data,
{
Expand Down

0 comments on commit b113f11

Please sign in to comment.