mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: add feature search service (#5149)
This commit is contained in:
parent
a5d304ca51
commit
3ee250ee7d
@ -0,0 +1,58 @@
|
||||
import useSWR, { SWRConfiguration } from 'swr';
|
||||
import { useCallback } from 'react';
|
||||
import { IFeatureToggleListItem } from 'interfaces/featureToggle';
|
||||
import { formatApiPath } from 'utils/formatPath';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
|
||||
type IFeatureSearchResponse = { features: IFeatureToggleListItem[] };
|
||||
|
||||
interface IUseFeatureSearchOutput {
|
||||
features: IFeatureSearchResponse;
|
||||
loading: boolean;
|
||||
error: string;
|
||||
refetch: () => void;
|
||||
}
|
||||
|
||||
const fallbackFeatures: { features: IFeatureToggleListItem[] } = {
|
||||
features: [],
|
||||
};
|
||||
|
||||
export const useFeatureSearch = (
|
||||
options: SWRConfiguration = {},
|
||||
): IUseFeatureSearchOutput => {
|
||||
const { KEY, fetcher } = getFeatureSearchFetcher();
|
||||
const { data, error, mutate } = useSWR<IFeatureSearchResponse>(
|
||||
KEY,
|
||||
fetcher,
|
||||
options,
|
||||
);
|
||||
|
||||
const refetch = useCallback(() => {
|
||||
mutate();
|
||||
}, [mutate]);
|
||||
|
||||
return {
|
||||
features: data || fallbackFeatures,
|
||||
loading: !error && !data,
|
||||
error,
|
||||
refetch,
|
||||
};
|
||||
};
|
||||
|
||||
const getFeatureSearchFetcher = () => {
|
||||
const fetcher = () => {
|
||||
const path = formatApiPath(`api/admin/search/features`);
|
||||
return fetch(path, {
|
||||
method: 'GET',
|
||||
})
|
||||
.then(handleErrorResponses('Feature search'))
|
||||
.then((res) => res.json());
|
||||
};
|
||||
|
||||
const KEY = `api/admin/search/features`;
|
||||
|
||||
return {
|
||||
fetcher,
|
||||
KEY,
|
||||
};
|
||||
};
|
@ -0,0 +1,35 @@
|
||||
import { Db } from '../../db/db';
|
||||
import { IUnleashConfig } from '../../types';
|
||||
|
||||
import FeatureStrategiesStore from '../feature-toggle/feature-toggle-strategies-store';
|
||||
import { FeatureSearchService } from './feature-search-service';
|
||||
import FakeFeatureStrategiesStore from '../feature-toggle/fakes/fake-feature-strategies-store';
|
||||
|
||||
export const createFeatureSearchService =
|
||||
(config: IUnleashConfig) => (db: Db): FeatureSearchService => {
|
||||
const { getLogger, eventBus, flagResolver } = config;
|
||||
const featureStrategiesStore = new FeatureStrategiesStore(
|
||||
db,
|
||||
eventBus,
|
||||
getLogger,
|
||||
flagResolver,
|
||||
);
|
||||
|
||||
return new FeatureSearchService(
|
||||
{ featureStrategiesStore: featureStrategiesStore },
|
||||
config,
|
||||
);
|
||||
};
|
||||
|
||||
export const createFakeFeatureSearchService = (
|
||||
config: IUnleashConfig,
|
||||
): FeatureSearchService => {
|
||||
const fakeFeatureStrategiesStore = new FakeFeatureStrategiesStore();
|
||||
|
||||
return new FeatureSearchService(
|
||||
{
|
||||
featureStrategiesStore: fakeFeatureStrategiesStore,
|
||||
},
|
||||
config,
|
||||
);
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
import { Response } from 'express';
|
||||
import Controller from '../../routes/controller';
|
||||
import { OpenApiService } from '../../services';
|
||||
import { FeatureSearchService, OpenApiService } from '../../services';
|
||||
import {
|
||||
IFlagResolver,
|
||||
IUnleashConfig,
|
||||
@ -19,22 +19,28 @@ interface ISearchQueryParams {
|
||||
|
||||
const PATH = '/features';
|
||||
|
||||
type FeatureSearchServices = Pick<IUnleashServices, 'openApiService'>;
|
||||
type FeatureSearchServices = Pick<
|
||||
IUnleashServices,
|
||||
'openApiService' | 'featureSearchService'
|
||||
>;
|
||||
|
||||
export default class FeatureSearchController extends Controller {
|
||||
private openApiService: OpenApiService;
|
||||
|
||||
private flagResolver: IFlagResolver;
|
||||
|
||||
private featureSearchService: FeatureSearchService;
|
||||
|
||||
private readonly logger: Logger;
|
||||
|
||||
constructor(
|
||||
config: IUnleashConfig,
|
||||
{ openApiService }: FeatureSearchServices,
|
||||
{ openApiService, featureSearchService }: FeatureSearchServices,
|
||||
) {
|
||||
super(config);
|
||||
this.openApiService = openApiService;
|
||||
this.flagResolver = config.flagResolver;
|
||||
this.featureSearchService = featureSearchService;
|
||||
this.logger = config.getLogger(
|
||||
'/feature-search/feature-search-controller.ts',
|
||||
);
|
||||
@ -66,7 +72,11 @@ export default class FeatureSearchController extends Controller {
|
||||
const { query, tags } = req.query;
|
||||
|
||||
if (this.config.flagResolver.isEnabled('featureSearchAPI')) {
|
||||
res.json({ features: [] });
|
||||
const features = await this.featureSearchService.search(
|
||||
query,
|
||||
tags,
|
||||
);
|
||||
res.json({ features });
|
||||
} else {
|
||||
throw new InvalidOperationError(
|
||||
'Feature Search API is not enabled',
|
||||
|
29
src/lib/features/feature-search/feature-search-service.ts
Normal file
29
src/lib/features/feature-search/feature-search-service.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { Logger } from '../../logger';
|
||||
import {
|
||||
IFeatureStrategiesStore,
|
||||
IUnleashConfig,
|
||||
IUnleashStores,
|
||||
} from '../../types';
|
||||
|
||||
export class FeatureSearchService {
|
||||
private featureStrategiesStore: IFeatureStrategiesStore;
|
||||
private logger: Logger;
|
||||
constructor(
|
||||
{
|
||||
featureStrategiesStore,
|
||||
}: Pick<IUnleashStores, 'featureStrategiesStore'>,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
) {
|
||||
this.featureStrategiesStore = featureStrategiesStore;
|
||||
this.logger = getLogger('services/feature-search-service.ts');
|
||||
}
|
||||
|
||||
async search(query: string, tags: string[]) {
|
||||
const features = await this.featureStrategiesStore.getFeatureOverview({
|
||||
projectId: 'default',
|
||||
});
|
||||
|
||||
return features;
|
||||
// Search for features
|
||||
}
|
||||
}
|
@ -99,6 +99,11 @@ import {
|
||||
createFakeClientFeatureToggleService,
|
||||
} from '../features/client-feature-toggles/createClientFeatureToggleService';
|
||||
import { ClientFeatureToggleService } from '../features/client-feature-toggles/client-feature-toggle-service';
|
||||
import {
|
||||
createFeatureSearchService,
|
||||
createFakeFeatureSearchService,
|
||||
} from '../features/feature-search/createFeatureSearchService';
|
||||
import { FeatureSearchService } from '../features/feature-search/feature-search-service';
|
||||
|
||||
// TODO: will be moved to scheduler feature directory
|
||||
export const scheduleServices = async (
|
||||
@ -336,6 +341,10 @@ export const createServices = (
|
||||
: withFakeTransactional(createFakeDependentFeaturesService(config));
|
||||
const dependentFeaturesService = transactionalDependentFeaturesService;
|
||||
|
||||
const featureSearchService = db
|
||||
? createFeatureSearchService(config)(db)
|
||||
: createFakeFeatureSearchService(config);
|
||||
|
||||
const featureToggleServiceV2 = new FeatureToggleService(
|
||||
stores,
|
||||
config,
|
||||
@ -483,6 +492,7 @@ export const createServices = (
|
||||
dependentFeaturesService,
|
||||
transactionalDependentFeaturesService,
|
||||
clientFeatureToggleService,
|
||||
featureSearchService,
|
||||
};
|
||||
};
|
||||
|
||||
@ -528,4 +538,5 @@ export {
|
||||
SchedulerService,
|
||||
DependentFeaturesService,
|
||||
ClientFeatureToggleService,
|
||||
FeatureSearchService,
|
||||
};
|
||||
|
@ -50,6 +50,7 @@ import { IPrivateProjectChecker } from '../features/private-project/privateProje
|
||||
import { DependentFeaturesService } from '../features/dependent-features/dependent-features-service';
|
||||
import { WithTransactional } from 'lib/db/transaction';
|
||||
import { ClientFeatureToggleService } from 'lib/features/client-feature-toggles/client-feature-toggle-service';
|
||||
import { FeatureSearchService } from 'lib/features/feature-search/feature-search-service';
|
||||
|
||||
export interface IUnleashServices {
|
||||
accessService: AccessService;
|
||||
@ -107,4 +108,5 @@ export interface IUnleashServices {
|
||||
dependentFeaturesService: DependentFeaturesService;
|
||||
transactionalDependentFeaturesService: WithTransactional<DependentFeaturesService>;
|
||||
clientFeatureToggleService: ClientFeatureToggleService;
|
||||
featureSearchService: FeatureSearchService;
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ process.nextTick(async () => {
|
||||
separateAdminClientApi: true,
|
||||
playgroundImprovements: true,
|
||||
featureSwitchRefactor: true,
|
||||
featureSearchAPI: true,
|
||||
},
|
||||
},
|
||||
authentication: {
|
||||
|
Loading…
Reference in New Issue
Block a user