1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-11 00:08:30 +01:00

fix: reducing of features will not break order anymore (#5654)

This commit is contained in:
Jaanus Sellin 2023-12-15 14:46:40 +02:00 committed by GitHub
parent 8283edfc0a
commit dafec2e672
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 41 deletions

View File

@ -19,8 +19,8 @@ import {
} from '../feature-toggle/types/feature-toggle-strategies-store-type';
import FeatureStrategiesStore from '../feature-toggle/feature-toggle-strategies-store';
const sortEnvironments = (overview: IFeatureOverview) => {
return Object.values(overview).map((data: IFeatureOverview) => ({
const sortEnvironments = (overview: IFeatureOverview[]) => {
return overview.map((data: IFeatureOverview) => ({
...data,
environments: data.environments
.filter((f) => f.name)
@ -296,34 +296,16 @@ class FeatureSearchStore implements IFeatureSearchStore {
};
}
getAggregatedSearchData(rows): IFeatureOverview {
return rows.reduce((acc, row) => {
if (acc[row.feature_name] !== undefined) {
const environmentExists = acc[
row.feature_name
].environments.some(
(existingEnvironment) =>
existingEnvironment.name === row.environment,
);
if (!environmentExists) {
acc[row.feature_name].environments.push(
FeatureSearchStore.getEnvironment(row),
);
}
getAggregatedSearchData(rows): IFeatureOverview[] {
const entriesMap: Map<string, IFeatureOverview> = new Map();
const orderedEntries: IFeatureOverview[] = [];
const segmentExists = acc[row.feature_name].segments.includes(
row.segment_name,
);
rows.forEach((row) => {
let entry = entriesMap.get(row.feature_name);
if (row.segment_name && !segmentExists) {
acc[row.feature_name].segments.push(row.segment_name);
}
if (this.isNewTag(acc[row.feature_name], row)) {
this.addTag(acc[row.feature_name], row);
}
} else {
acc[row.feature_name] = {
if (!entry) {
// Create a new entry
entry = {
type: row.type,
description: row.description,
project: row.project,
@ -333,24 +315,41 @@ class FeatureSearchStore implements IFeatureSearchStore {
stale: row.stale,
impressionData: row.impression_data,
lastSeenAt: row.last_seen_at,
environments: [FeatureSearchStore.getEnvironment(row)],
environments: [],
segments: row.segment_name ? [row.segment_name] : [],
};
entriesMap.set(row.feature_name, entry);
orderedEntries.push(entry);
}
if (this.isNewTag(acc[row.feature_name], row)) {
this.addTag(acc[row.feature_name], row);
}
// Add environment if not already present
if (!entry.environments.some((e) => e.name === row.environment)) {
entry.environments.push(FeatureSearchStore.getEnvironment(row));
}
const featureRow = acc[row.feature_name];
// Add segment if not already present
if (
featureRow.lastSeenAt === undefined ||
new Date(row.env_last_seen_at) >
new Date(featureRow.last_seen_at)
row.segment_name &&
!entry.segments.includes(row.segment_name)
) {
featureRow.lastSeenAt = row.env_last_seen_at;
entry.segments.push(row.segment_name);
}
return acc;
}, {});
// Add tag if new
if (this.isNewTag(entry, row)) {
this.addTag(entry, row);
}
// Update lastSeenAt if more recent
if (
!entry.lastSeenAt ||
new Date(row.env_last_seen_at) > new Date(entry.lastSeenAt)
) {
entry.lastSeenAt = row.env_last_seen_at;
}
});
return orderedEntries;
}
private addTag(
@ -369,13 +368,16 @@ class FeatureSearchStore implements IFeatureSearchStore {
};
}
private isTagRow(row: Record<string, any>): boolean {
return row.tag_type && row.tag_value;
}
private isNewTag(
featureToggle: Record<string, any>,
row: Record<string, any>,
): boolean {
return (
row.tag_type &&
row.tag_value &&
this.isTagRow(row) &&
!featureToggle.tags?.some(
(tag) =>
tag.type === row.tag_type && tag.value === row.tag_value,

View File

@ -477,6 +477,31 @@ test('should sort features', async () => {
total: 3,
});
});
test('should sort features when feature names are numbers', async () => {
await app.createFeature('my_feature_a');
await app.createFeature('my_feature_c');
await app.createFeature('my_feature_b');
await app.createFeature('1234');
await app.favoriteFeature('my_feature_b');
const { body: favoriteSortByName } = await sortFeatures({
sortBy: 'name',
sortOrder: 'asc',
favoritesFirst: 'true',
});
expect(favoriteSortByName).toMatchObject({
features: [
{ name: 'my_feature_b' },
{ name: '1234' },
{ name: 'my_feature_a' },
{ name: 'my_feature_c' },
],
total: 4,
});
});
test('should paginate correctly when using tags', async () => {
await app.createFeature('my_feature_a');
await app.createFeature('my_feature_b');

View File

@ -205,6 +205,11 @@ export interface IEnvironmentOverview extends IEnvironmentBase {
export interface IFeatureOverview {
name: string;
description: string;
project: string;
favorite: boolean;
impressionData: boolean;
segments: string[];
type: string;
stale: boolean;
createdAt: Date;