Skip to content

Commit

Permalink
refactor/last seen at archived (#5102)
Browse files Browse the repository at this point in the history
Refactor global archive view and project archive view to include last
seen at by environment
  • Loading branch information
FredrikOseberg authored Oct 20, 2023
1 parent ba758e1 commit 71431c7
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 80 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Request, Response } from 'express';
import { IUnleashConfig } from '../../types/option';
import { IUnleashServices } from '../../types';
import Controller from '../controller';
import Controller from '../../routes/controller';
import { extractUsername } from '../../util/extract-user';
import { DELETE_FEATURE, NONE, UPDATE_FEATURE } from '../../types/permissions';
import FeatureToggleService from '../../features/feature-toggle/feature-toggle-service';
import { IAuthRequest } from '../unleash-types';
import FeatureToggleService from './feature-toggle-service';
import { IAuthRequest } from '../../routes/unleash-types';
import {
featuresSchema,
FeaturesSchema,
Expand Down Expand Up @@ -140,7 +140,7 @@ export default class ArchiveController extends Controller {
res: Response<FeaturesSchema>,
): Promise<void> {
const { user } = req;
const features = await this.featureService.getMetadataForAllFeatures(
const features = await this.featureService.getAllArchivedFeatures(
true,
user.id,
);
Expand All @@ -158,7 +158,7 @@ export default class ArchiveController extends Controller {
): Promise<void> {
const { projectId } = req.params;
const features =
await this.featureService.getMetadataForAllFeaturesByProjectId(
await this.featureService.getArchivedFeaturesByProjectId(
true,
projectId,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class FeatureToggleRowConverter {
const newEnvironment = {
name: row.last_seen_at_env,
lastSeenAt: row.env_last_seen_at,
enabled: row.enabled,
enabled: row.enabled || false,
};

feature.environments.push(newEnvironment);
Expand Down Expand Up @@ -253,4 +253,32 @@ export class FeatureToggleRowConverter {

return this.formatToggles(result);
};

buildArchivedFeatureToggleListFromRows = (
rows: any[],
): IFeatureToggleListItem[] => {
const result = rows.reduce((acc, row) => {
const feature: PartialDeep<IFeatureToggleListItem> =
acc[row.name] ?? {};

feature.name = row.name;
feature.description = row.description;
feature.type = row.type;
feature.project = row.project;
feature.stale = row.stale;
feature.createdAt = row.created_at;
feature.impressionData = row.impression_data;
feature.lastSeenAt = row.last_seen_at;
feature.archivedAt = row.archived_at;

if (this.flagResolver.isEnabled('useLastSeenRefactor')) {
this.addLastSeenByEnvironment(feature, row);
}

acc[row.name] = feature;
return acc;
}, {});

return Object.values(result);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ export default class FakeFeatureToggleStore implements IFeatureToggleStore {
return this.features.filter((feature) => feature.archived !== archived);
}

async getArchivedFeatures(project: string): Promise<FeatureToggle[]> {
return this.features.filter((feature) => feature.archived === true);
}

async getPlaygroundFeatures(
query?: IFeatureToggleQuery,
): Promise<FeatureConfigurationClient[]> {
Expand Down
19 changes: 15 additions & 4 deletions src/lib/features/feature-toggle/feature-toggle-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2032,11 +2032,18 @@ class FeatureToggleService {
);
}

async getMetadataForAllFeatures(
async getAllArchivedFeatures(
archived: boolean,
userId: number,
): Promise<FeatureToggle[]> {
const features = await this.featureToggleStore.getAll({ archived });
let features;

if (this.flagResolver.isEnabled('useLastSeenRefactor')) {
features = await this.featureToggleStore.getArchivedFeatures();
} else {
features = await this.featureToggleStore.getAll({ archived });
}

if (this.flagResolver.isEnabled('privateProjects')) {
const projectAccess =
await this.privateProjectChecker.getUserAccessibleProjects(
Expand All @@ -2053,11 +2060,15 @@ class FeatureToggleService {
return features;
}

async getMetadataForAllFeaturesByProjectId(
async getArchivedFeaturesByProjectId(
archived: boolean,
project: string,
): Promise<FeatureToggle[]> {
return this.featureToggleStore.getAll({ archived, project });
if (this.flagResolver.isEnabled('useLastSeenRefactor')) {
return this.featureToggleStore.getArchivedFeatures(project);
} else {
return this.featureToggleStore.getAll({ archived, project });
}
}

async getProjectId(name: string): Promise<string | undefined> {
Expand Down
63 changes: 61 additions & 2 deletions src/lib/features/feature-toggle/feature-toggle-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { FeatureToggleListBuilder } from './query-builders/feature-toggle-list-b
import { FeatureConfigurationClient } from './types/feature-toggle-strategies-store-type';
import { IFlagResolver } from '../../../lib/types';
import { FeatureToggleRowConverter } from './converters/feature-toggle-row-converter';
import FlagResolver from 'lib/util/flag-resolver';

export type EnvironmentFeatureNames = { [key: string]: string[] };

Expand Down Expand Up @@ -53,6 +52,17 @@ interface VariantDTO {
variants: IVariant[];
}

const commonSelectColumns = [
'features.name as name',
'features.description as description',
'features.type as type',
'features.project as project',
'features.stale as stale',
'features.impression_data as impression_data',
'features.last_seen_at as last_seen_at',
'features.created_at as created_at',
];

const TABLE = 'features';
const FEATURE_ENVIRONMENTS_TABLE = 'feature_environments';

Expand Down Expand Up @@ -117,7 +127,22 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
}

private getBaseFeatureQuery = (archived: boolean, environment: string) => {
const builder = new FeatureToggleListBuilder(this.db);
const builder = new FeatureToggleListBuilder(this.db, [
...commonSelectColumns,
'fe.variants as variants',
'fe.enabled as enabled',
'fe.environment as environment',
'fs.id as strategy_id',
'fs.strategy_name as strategy_name',
'fs.title as strategy_title',
'fs.disabled as strategy_disabled',
'fs.parameters as parameters',
'fs.constraints as constraints',
'fs.sort_order as sort_order',
'fs.variants as strategy_variants',
'segments.id as segment_id',
'segments.constraints as segment_constraints',
]);

builder
.query('features')
Expand Down Expand Up @@ -227,9 +252,43 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
.from(TABLE)
.where(rest)
.modify(FeatureToggleStore.filterByArchived, archived);

return rows.map(this.rowToFeature);
}

async getArchivedFeatures(project?: string): Promise<FeatureToggle[]> {
const builder = new FeatureToggleListBuilder(this.db, [
...commonSelectColumns,
'features.archived_at as archived_at',
]);

builder.query('features').withLastSeenByEnvironment();

builder.addSelectColumn(
'last_seen_at_metrics.last_seen_at as env_last_seen_at',
);
builder.addSelectColumn(
'last_seen_at_metrics.environment as last_seen_at_env',
);

let rows;

if (project) {
rows = await builder.internalQuery
.select(builder.getSelectColumns())
.where({ project })
.whereNotNull('archived_at');
} else {
rows = await builder.internalQuery
.select(builder.getSelectColumns())
.whereNotNull('archived_at');
}

return this.featureToggleRowConverter.buildArchivedFeatureToggleListFromRows(
rows,
);
}

async getAllByNames(names: string[]): Promise<FeatureToggle[]> {
const query = this.db<FeaturesTable>(TABLE).orderBy('name', 'asc');
query.whereIn('name', names);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,9 @@ export class FeatureToggleListBuilder {

private selectColumns: (string | Knex.Raw<any>)[];

constructor(db) {
constructor(db, selectColumns) {
this.db = db;
this.selectColumns = [
'features.name as name',
'features.description as description',
'features.type as type',
'features.project as project',
'features.stale as stale',
'features.impression_data as impression_data',
'features.last_seen_at as last_seen_at',
'features.created_at as created_at',
'fe.variants as variants',
'fe.enabled as enabled',
'fe.environment as environment',
'fs.id as strategy_id',
'fs.strategy_name as strategy_name',
'fs.title as strategy_title',
'fs.disabled as strategy_disabled',
'fs.parameters as parameters',
'fs.constraints as constraints',
'fs.sort_order as sort_order',
'fs.variants as strategy_variants',
'segments.id as segment_id',
'segments.constraints as segment_constraints',
] as (string | Knex.Raw<any>)[];
this.selectColumns = selectColumns;
}

getSelectColumns = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import dbInit, { ITestDb } from '../../helpers/database-init';
import dbInit, { ITestDb } from '../../../../test/e2e/helpers/database-init';
import {
IUnleashTest,
setupAppWithCustomConfig,
} from '../../helpers/test-helper';
import getLogger from '../../../fixtures/no-logger';
} from '../../../../test/e2e/helpers/test-helper';
import getLogger from '../../../../test/fixtures/no-logger';

let app: IUnleashTest;
let db: ITestDb;
Expand Down
Loading

0 comments on commit 71431c7

Please sign in to comment.