mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-01 00:08:27 +01:00
f1e95108d1
Extracts the Avatar Group component into a `common` component and adds a standard tooltip to all avatars. Relates to linear issue 1-2606 This is a suggestion / proof of concept for how we can solve it. While I think we can merge this as is, I'd also be happy to take any discussions on other ways to approach it etc. ## Why are these changes made together? Because extracting the avatar group without adding the new tooltip data made the existing tooltip misbehave (it'd show up in the top left of the screen, not synced to the avatar in any way). I probably could have (and still can if you think it's prudent) split it out such that the avatar gets a standardized tooltip first (and disable it for the group card avatars), and split out the avatars in a follow-up. Happy to do that if you think it's better. ## What does this mean? It used to be that we had no consistent way of dealing with avatars and tooltips. Some places had them, some places didn't. This change makes it so that all avatars that we can show tooltips for will get the same tooltip. Previously, we had at least 4 different ways of dealing with tooltips: - The HTML tooltip (that would be standardized with this PR) in the project flags table ![image](https://github.com/user-attachments/assets/91098d31-a5e3-4091-9125-332fe5d106fd) - The "title" that you'd get on your user avatar ![image](https://github.com/user-attachments/assets/39062b61-db8c-4bd5-9fa3-3ecc9bc192ee) - The group card list tooltip ![image](https://github.com/user-attachments/assets/0d4a696a-e944-446c-8bff-4dcec02d8afb) - And sometimes you'd get nothing at all ![image](https://github.com/user-attachments/assets/8975afaf-9ca1-4eb6-b443-9ab94b52bbd8) with this change, we'll always show the same kind of tooltip if we can: ![image](https://github.com/user-attachments/assets/974c592c-c844-4b65-8a55-05e84d3df130) ## What goes in the tooltip? We use the `UserAvatar` component for a fair few different things and I didn't want to extract separate components for all the different use cases. Instead, I wanted to get an overview over what we use it for and what is relevant info to show. I found all the places we used it and tried to form an opinion. This tooltip will work with a user's email, name, username, and id. If there is no user (such as for empty avatars and avatars displaying only "+n" for remaining members), we show no tooltip. Following the example set by the group card avatars, we'll try to use email or username (in that order) as the main bit of text. If the user has an email or a username and also a name, the name will be used as secondary text. If the user does not have an email or username, but has a name, we'll use the name as the main text. If the user does not have an email, a username, or a name, we'll try to show "User ID: N" if they have an id. If they do not have a username, a name, an email, or an ID, we bail out and show nothing. ## Why can you disable the tooltip? In some cases, you might want to disable the tooltip because you have more information to feed into it. An example of that is in the project flags table, where we want to show more information in cases where the user is 'unknown': ![image](https://github.com/user-attachments/assets/758b4e86-e934-47e3-91ce-ce900f76bc54) ## Additional fixes This PR also adds a few lines of CSS to fix a minor avatar layout bug. Before: ![image](https://github.com/user-attachments/assets/0150efbf-c51a-40bb-898f-7ddd3565ce21) After: ![image](https://github.com/user-attachments/assets/f337cf68-c572-4610-b1de-a27749325da8)
144 lines
2.9 KiB
TypeScript
144 lines
2.9 KiB
TypeScript
import type { IFeatureStrategy } from './strategy';
|
|
import type { ITag } from './tags';
|
|
|
|
/**
|
|
* @deprecated use FeatureSchema from openapi
|
|
*/
|
|
export interface IFeatureFlagListItem {
|
|
type: string;
|
|
name: string;
|
|
stale?: boolean;
|
|
lastSeenAt?: string;
|
|
createdAt: string;
|
|
environments: IEnvironments[];
|
|
tags?: ITag[];
|
|
favorite?: boolean;
|
|
}
|
|
|
|
export interface IEnvironments {
|
|
name: string;
|
|
enabled: boolean;
|
|
variantCount: number;
|
|
lastSeenAt?: string | null;
|
|
type?: string;
|
|
hasStrategies?: boolean;
|
|
hasEnabledStrategies?: boolean;
|
|
yes?: number;
|
|
no?: number;
|
|
}
|
|
|
|
export type ILastSeenEnvironments = Pick<
|
|
IEnvironments,
|
|
'name' | 'enabled' | 'lastSeenAt' | 'yes' | 'no'
|
|
>;
|
|
|
|
export type Lifecycle = {
|
|
stage: 'initial' | 'pre-live' | 'live' | 'completed' | 'archived';
|
|
status?: string;
|
|
enteredStageAt: string;
|
|
};
|
|
|
|
export type Collaborator = {
|
|
id: number;
|
|
name: string;
|
|
imageUrl: string;
|
|
};
|
|
|
|
export type CollaboratorData = {
|
|
users: Collaborator[];
|
|
};
|
|
|
|
/**
|
|
* @deprecated use FeatureSchema from openapi
|
|
*/
|
|
export interface IFeatureToggle {
|
|
stale: boolean;
|
|
archived: boolean;
|
|
enabled?: boolean;
|
|
createdAt: string;
|
|
lastSeenAt?: string;
|
|
description?: string;
|
|
environments: IFeatureEnvironment[];
|
|
name: string;
|
|
|
|
favorite: boolean;
|
|
project: string;
|
|
type: string;
|
|
variants: IFeatureVariant[];
|
|
impressionData: boolean;
|
|
strategies?: IFeatureStrategy[];
|
|
dependencies: Array<IDependency>;
|
|
lifecycle?: Lifecycle;
|
|
children: Array<string>;
|
|
createdBy?: {
|
|
id: number;
|
|
name: string;
|
|
imageUrl: string;
|
|
};
|
|
collaborators?: CollaboratorData;
|
|
}
|
|
|
|
export interface IDependency {
|
|
feature: string;
|
|
enabled?: boolean;
|
|
variants?: string[];
|
|
}
|
|
|
|
export interface IFeatureEnvironment {
|
|
type: string;
|
|
name: string;
|
|
enabled: boolean;
|
|
strategies: IFeatureStrategy[];
|
|
variants?: IFeatureVariant[];
|
|
lastSeenAt?: string;
|
|
yes?: number;
|
|
no?: number;
|
|
}
|
|
|
|
export interface IFeatureEnvironmentWithCrEnabled extends IFeatureEnvironment {
|
|
crEnabled?: boolean;
|
|
}
|
|
|
|
export interface IFeatureVariant {
|
|
name: string;
|
|
stickiness: string;
|
|
weight: number;
|
|
weightType: 'fix' | 'variable';
|
|
overrides?: IOverride[];
|
|
payload?: IPayload;
|
|
}
|
|
|
|
export interface IOverride {
|
|
contextName: string;
|
|
values: string[];
|
|
}
|
|
|
|
export interface IPayload {
|
|
type: string;
|
|
value: string;
|
|
}
|
|
|
|
export interface IFeatureEnvironmentMetrics {
|
|
environment: string;
|
|
timestamp: string;
|
|
yes: number;
|
|
no: number;
|
|
}
|
|
|
|
export interface IFeatureMetrics {
|
|
version?: number;
|
|
maturity?: string;
|
|
lastHourUsage: IFeatureEnvironmentMetrics[];
|
|
seenApplications: string[];
|
|
}
|
|
|
|
export interface IFeatureMetricsRaw {
|
|
featureName: string;
|
|
appName: string;
|
|
environment: string;
|
|
timestamp: string;
|
|
yes: number;
|
|
no: number;
|
|
variants?: Record<string, number>;
|
|
}
|