d5279b124f
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
57 lines
2.0 KiB
TypeScript
57 lines
2.0 KiB
TypeScript
import type { UserLoginActivity } from "../../types/api";
|
|
|
|
export type DisplayLoginActivity = UserLoginActivity & { grouped_count: number };
|
|
|
|
type ActivityStatus = NonNullable<UserLoginActivity["activity_status"]>;
|
|
|
|
const activityTime = (value: string) => new Date(value).getTime();
|
|
|
|
export const activitySourceKey = (item: UserLoginActivity) => {
|
|
if (!item.login_ip) return `session:${item.id}`;
|
|
return [item.client_type, item.login_ip].join("|");
|
|
};
|
|
|
|
export const groupLoginActivitiesBySource = (
|
|
activities: UserLoginActivity[],
|
|
resolveStatus: (item: UserLoginActivity) => ActivityStatus,
|
|
): DisplayLoginActivity[] => {
|
|
const grouped = new Map<
|
|
string,
|
|
{ row: DisplayLoginActivity; firstLoginAt: string; hasOnlineSession: boolean }
|
|
>();
|
|
|
|
activities.forEach((item) => {
|
|
const key = activitySourceKey(item);
|
|
const status = resolveStatus(item);
|
|
const existing = grouped.get(key);
|
|
if (!existing) {
|
|
grouped.set(key, {
|
|
row: { ...item, activity_status: status, grouped_count: 1 },
|
|
firstLoginAt: item.login_at,
|
|
hasOnlineSession: status === "ONLINE",
|
|
});
|
|
return;
|
|
}
|
|
|
|
existing.row.grouped_count += 1;
|
|
existing.hasOnlineSession ||= status === "ONLINE";
|
|
if (activityTime(item.login_at) < activityTime(existing.firstLoginAt)) {
|
|
existing.firstLoginAt = item.login_at;
|
|
}
|
|
if (activityTime(item.last_seen_at) > activityTime(existing.row.last_seen_at)) {
|
|
const groupedCount = existing.row.grouped_count;
|
|
existing.row = { ...item, activity_status: status, grouped_count: groupedCount };
|
|
}
|
|
});
|
|
|
|
return Array.from(grouped.values())
|
|
.map(({ row, firstLoginAt, hasOnlineSession }) => ({
|
|
...row,
|
|
login_at: firstLoginAt,
|
|
activity_status: hasOnlineSession ? "ONLINE" : row.activity_status,
|
|
ended_at: hasOnlineSession ? null : row.ended_at,
|
|
end_reason: hasOnlineSession ? null : row.end_reason,
|
|
}))
|
|
.sort((left, right) => activityTime(right.last_seen_at) - activityTime(left.last_seen_at));
|
|
};
|