mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
fix: reducing of features will not break order anymore (#5654)
This commit is contained in:
parent
8283edfc0a
commit
dafec2e672
@ -19,8 +19,8 @@ import {
|
|||||||
} from '../feature-toggle/types/feature-toggle-strategies-store-type';
|
} from '../feature-toggle/types/feature-toggle-strategies-store-type';
|
||||||
import FeatureStrategiesStore from '../feature-toggle/feature-toggle-strategies-store';
|
import FeatureStrategiesStore from '../feature-toggle/feature-toggle-strategies-store';
|
||||||
|
|
||||||
const sortEnvironments = (overview: IFeatureOverview) => {
|
const sortEnvironments = (overview: IFeatureOverview[]) => {
|
||||||
return Object.values(overview).map((data: IFeatureOverview) => ({
|
return overview.map((data: IFeatureOverview) => ({
|
||||||
...data,
|
...data,
|
||||||
environments: data.environments
|
environments: data.environments
|
||||||
.filter((f) => f.name)
|
.filter((f) => f.name)
|
||||||
@ -296,34 +296,16 @@ class FeatureSearchStore implements IFeatureSearchStore {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getAggregatedSearchData(rows): IFeatureOverview {
|
getAggregatedSearchData(rows): IFeatureOverview[] {
|
||||||
return rows.reduce((acc, row) => {
|
const entriesMap: Map<string, IFeatureOverview> = new Map();
|
||||||
if (acc[row.feature_name] !== undefined) {
|
const orderedEntries: IFeatureOverview[] = [];
|
||||||
const environmentExists = acc[
|
|
||||||
row.feature_name
|
|
||||||
].environments.some(
|
|
||||||
(existingEnvironment) =>
|
|
||||||
existingEnvironment.name === row.environment,
|
|
||||||
);
|
|
||||||
if (!environmentExists) {
|
|
||||||
acc[row.feature_name].environments.push(
|
|
||||||
FeatureSearchStore.getEnvironment(row),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const segmentExists = acc[row.feature_name].segments.includes(
|
rows.forEach((row) => {
|
||||||
row.segment_name,
|
let entry = entriesMap.get(row.feature_name);
|
||||||
);
|
|
||||||
|
|
||||||
if (row.segment_name && !segmentExists) {
|
if (!entry) {
|
||||||
acc[row.feature_name].segments.push(row.segment_name);
|
// Create a new entry
|
||||||
}
|
entry = {
|
||||||
|
|
||||||
if (this.isNewTag(acc[row.feature_name], row)) {
|
|
||||||
this.addTag(acc[row.feature_name], row);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
acc[row.feature_name] = {
|
|
||||||
type: row.type,
|
type: row.type,
|
||||||
description: row.description,
|
description: row.description,
|
||||||
project: row.project,
|
project: row.project,
|
||||||
@ -333,24 +315,41 @@ class FeatureSearchStore implements IFeatureSearchStore {
|
|||||||
stale: row.stale,
|
stale: row.stale,
|
||||||
impressionData: row.impression_data,
|
impressionData: row.impression_data,
|
||||||
lastSeenAt: row.last_seen_at,
|
lastSeenAt: row.last_seen_at,
|
||||||
environments: [FeatureSearchStore.getEnvironment(row)],
|
environments: [],
|
||||||
segments: row.segment_name ? [row.segment_name] : [],
|
segments: row.segment_name ? [row.segment_name] : [],
|
||||||
};
|
};
|
||||||
|
entriesMap.set(row.feature_name, entry);
|
||||||
|
orderedEntries.push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.isNewTag(acc[row.feature_name], row)) {
|
// Add environment if not already present
|
||||||
this.addTag(acc[row.feature_name], row);
|
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 (
|
if (
|
||||||
featureRow.lastSeenAt === undefined ||
|
row.segment_name &&
|
||||||
new Date(row.env_last_seen_at) >
|
!entry.segments.includes(row.segment_name)
|
||||||
new Date(featureRow.last_seen_at)
|
|
||||||
) {
|
) {
|
||||||
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(
|
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(
|
private isNewTag(
|
||||||
featureToggle: Record<string, any>,
|
featureToggle: Record<string, any>,
|
||||||
row: Record<string, any>,
|
row: Record<string, any>,
|
||||||
): boolean {
|
): boolean {
|
||||||
return (
|
return (
|
||||||
row.tag_type &&
|
this.isTagRow(row) &&
|
||||||
row.tag_value &&
|
|
||||||
!featureToggle.tags?.some(
|
!featureToggle.tags?.some(
|
||||||
(tag) =>
|
(tag) =>
|
||||||
tag.type === row.tag_type && tag.value === row.tag_value,
|
tag.type === row.tag_type && tag.value === row.tag_value,
|
||||||
|
@ -477,6 +477,31 @@ test('should sort features', async () => {
|
|||||||
total: 3,
|
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 () => {
|
test('should paginate correctly when using tags', async () => {
|
||||||
await app.createFeature('my_feature_a');
|
await app.createFeature('my_feature_a');
|
||||||
await app.createFeature('my_feature_b');
|
await app.createFeature('my_feature_b');
|
||||||
|
@ -205,6 +205,11 @@ export interface IEnvironmentOverview extends IEnvironmentBase {
|
|||||||
|
|
||||||
export interface IFeatureOverview {
|
export interface IFeatureOverview {
|
||||||
name: string;
|
name: string;
|
||||||
|
description: string;
|
||||||
|
project: string;
|
||||||
|
favorite: boolean;
|
||||||
|
impressionData: boolean;
|
||||||
|
segments: string[];
|
||||||
type: string;
|
type: string;
|
||||||
stale: boolean;
|
stale: boolean;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
Loading…
Reference in New Issue
Block a user