1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-12 01:17:04 +02:00

Feat: feature view created by field - frontend (#7382)

add "Created by:" to feature overview meta and align other items
This commit is contained in:
Tymoteusz Czech 2024-06-13 13:00:57 +02:00 committed by GitHub
parent 906940948b
commit 582b33e121
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 65 additions and 2 deletions

View File

@ -25,7 +25,7 @@ interface IPermissionIconButtonProps {
edge?: IconButtonProps['edge'];
tooltipProps?: Omit<ITooltipResolverProps, 'children'>;
sx?: IconButtonProps['sx'];
size?: string;
size?: 'small' | 'medium' | 'large';
}
interface IButtonProps extends IPermissionIconButtonProps {
@ -87,7 +87,7 @@ const BasePermissionIconButton = ({
{...rest}
disabled={!access || disabled}
aria-labelledby={id}
size='large'
size={rest.size || 'large'}
>
{children}
</IconButton>

View File

@ -107,12 +107,16 @@ export const DependencyRow: FC<{ feature: IFeatureToggle }> = ({ feature }) => {
<StyledDetail>
<StyledLabel>Dependency:</StyledLabel>
<PermissionButton
size='small'
permission={UPDATE_FEATURE_DEPENDENCY}
projectId={feature.project}
variant='text'
onClick={() => {
setShowDependencyDialogue(true);
}}
sx={(theme) => ({
marginBottom: theme.spacing(0.4),
})}
>
Add parent feature
</PermissionButton>

View File

@ -21,6 +21,7 @@ import { useShowDependentFeatures } from './useShowDependentFeatures';
import type { ILastSeenEnvironments } from 'interfaces/featureToggle';
import { FeatureLifecycle } from '../FeatureLifecycle/FeatureLifecycle';
import { MarkCompletedDialogue } from '../FeatureLifecycle/MarkCompletedDialogue';
import { UserAvatar } from 'component/common/UserAvatar/UserAvatar';
const StyledContainer = styled('div')(({ theme }) => ({
borderRadius: theme.shape.borderRadiusLarge,
@ -83,6 +84,10 @@ const StyledDescription = styled('p')({
wordBreak: 'break-word',
});
const StyledUserAvatar = styled(UserAvatar)(({ theme }) => ({
margin: theme.spacing(1),
}));
export const StyledLabel = styled('span')(({ theme }) => ({
color: theme.palette.text.secondary,
marginRight: theme.spacing(1),
@ -98,6 +103,7 @@ const FeatureOverviewMetaData = () => {
const [showDelDialog, setShowDelDialog] = useState(false);
const [showMarkCompletedDialogue, setShowMarkCompletedDialogue] =
useState(false);
const flagCreatorEnabled = useUiFlag('flagCreator');
const { locationSettings } = useLocationSettings();
const showDependentFeatures = useShowDependentFeatures(feature.project);
@ -166,6 +172,7 @@ const FeatureOverviewMetaData = () => {
{description}
</StyledDescription>
<PermissionIconButton
size='medium'
projectId={projectId}
permission={UPDATE_FEATURE}
component={Link}
@ -184,6 +191,7 @@ const FeatureOverviewMetaData = () => {
<StyledDescriptionContainer>
No description.{' '}
<PermissionIconButton
size='medium'
projectId={projectId}
permission={UPDATE_FEATURE}
component={Link}
@ -216,6 +224,24 @@ const FeatureOverviewMetaData = () => {
/>
</StyledDetailsContainer>
</BodyItemWithIcon>
<ConditionallyRender
condition={
Boolean(feature.createdBy) && flagCreatorEnabled
}
show={() => (
<BodyItemWithIcon>
<StyledDetailsContainer>
<StyledDetail>
<StyledLabel>Created by:</StyledLabel>
<span>{feature.createdBy?.name}</span>
</StyledDetail>
<StyledUserAvatar
src={feature.createdBy?.imageUrl}
/>
</StyledDetailsContainer>
</BodyItemWithIcon>
)}
/>
<ConditionallyRender
condition={showDependentFeatures}
show={<DependencyRow feature={feature} />}

View File

@ -38,6 +38,9 @@ export type Lifecycle = {
enteredStageAt: string;
};
/**
* @deprecated use FeatureSchema from openapi
*/
export interface IFeatureToggle {
stale: boolean;
archived: boolean;
@ -57,6 +60,11 @@ export interface IFeatureToggle {
dependencies: Array<IDependency>;
lifecycle?: Lifecycle;
children: Array<string>;
createdBy?: {
id: string;
name: string;
imageUrl: string;
};
}
export interface IDependency {

View File

@ -3,6 +3,7 @@
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { FeatureSchemaCreatedBy } from './featureSchemaCreatedBy';
import type { FeatureSchemaDependenciesItem } from './featureSchemaDependenciesItem';
import type { FeatureEnvironmentSchema } from './featureEnvironmentSchema';
import type { FeatureSchemaLifecycle } from './featureSchemaLifecycle';
@ -28,6 +29,8 @@ export interface FeatureSchema {
* @nullable
*/
createdAt?: string | null;
/** User who created the feature flag */
createdBy?: FeatureSchemaCreatedBy;
/** The list of parent dependencies. This is an experimental field and may change. */
dependencies?: FeatureSchemaDependenciesItem[];
/**

View File

@ -0,0 +1,17 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
/**
* User who created the feature flag
*/
export type FeatureSchemaCreatedBy = {
/** The user id */
id: number;
/** URL used for the user profile image */
imageUrl: string;
/** Name of the user */
name: string;
};

View File

@ -543,6 +543,7 @@ export * from './featureLifecycleSchemaItem';
export * from './featureLifecycleSchemaItemStage';
export * from './featureMetricsSchema';
export * from './featureSchema';
export * from './featureSchemaCreatedBy';
export * from './featureSchemaDependenciesItem';
export * from './featureSchemaLifecycle';
export * from './featureSchemaLifecycleStage';

View File

@ -21,6 +21,10 @@ export type SearchFeaturesParams = {
* The feature flag type to filter by. The type can be specified with an operator. The supported operators are IS, IS_NOT, IS_ANY_OF, IS_NONE_OF.
*/
type?: string;
/**
* The feature flag creator to filter by. The creators can be specified with an operator. The supported operators are IS, IS_NOT, IS_ANY_OF, IS_NONE_OF.
*/
createdBy?: string;
/**
* The list of feature tags to filter by. Feature tag has to specify a type and a value joined with a colon.
*/