diff --git a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx
index d83a980c15..f5d77476c4 100644
--- a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx
+++ b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx
@@ -90,27 +90,23 @@ export const FeatureToggleListTable: VFC = () => {
const columns = useMemo(
() => [
- ...(uiConfig?.flags?.favorites
- ? [
- {
- Header: (
-
- ),
- accessor: 'favorite',
- Cell: ({ row: { original: feature } }: any) => (
- onFavorite(feature)}
- />
- ),
- maxWidth: 50,
- disableSortBy: true,
- },
- ]
- : []),
+ {
+ Header: (
+
+ ),
+ accessor: 'favorite',
+ Cell: ({ row: { original: feature } }: any) => (
+ onFavorite(feature)}
+ />
+ ),
+ maxWidth: 50,
+ disableSortBy: true,
+ },
{
Header: 'Seen',
accessor: 'lastSeenAt',
@@ -179,7 +175,7 @@ export const FeatureToggleListTable: VFC = () => {
searchable: true,
},
],
- [isFavoritesPinned, uiConfig?.flags?.favorites]
+ [isFavoritesPinned]
);
const {
diff --git a/frontend/src/component/feature/FeatureView/FeatureView.tsx b/frontend/src/component/feature/FeatureView/FeatureView.tsx
index 49c2e5bf10..34f46e6e5d 100644
--- a/frontend/src/component/feature/FeatureView/FeatureView.tsx
+++ b/frontend/src/component/feature/FeatureView/FeatureView.tsx
@@ -115,16 +115,9 @@ export const FeatureView = () => {
-
(
-
- )}
+
{
- (
-
- )}
+
diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx
index 3c7fc5b667..c5dcac15b3 100644
--- a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx
+++ b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx
@@ -193,28 +193,24 @@ export const ProjectFeatureToggles = ({
const columns = useMemo(
() => [
- ...(uiConfig?.flags?.favorites
- ? [
- {
- id: 'favorite',
- Header: (
-
- ),
- accessor: 'favorite',
- Cell: ({ row: { original: feature } }: any) => (
- onFavorite(feature)}
- />
- ),
- maxWidth: 50,
- disableSortBy: true,
- },
- ]
- : []),
+ {
+ id: 'favorite',
+ Header: (
+
+ ),
+ accessor: 'favorite',
+ Cell: ({ row: { original: feature } }: any) => (
+ onFavorite(feature)}
+ />
+ ),
+ maxWidth: 50,
+ disableSortBy: true,
+ },
{
Header: 'Seen',
accessor: 'lastSeenAt',
@@ -303,7 +299,7 @@ export const ProjectFeatureToggles = ({
disableSortBy: true,
},
],
- [projectId, environments, loading, onToggle, uiConfig?.flags?.favorites]
+ [projectId, environments, loading, onToggle]
);
const [searchValue, setSearchValue] = useState(
diff --git a/frontend/src/component/project/ProjectCard/ProjectCard.tsx b/frontend/src/component/project/ProjectCard/ProjectCard.tsx
index defd9fcfaa..a16ee83ebe 100644
--- a/frontend/src/component/project/ProjectCard/ProjectCard.tsx
+++ b/frontend/src/component/project/ProjectCard/ProjectCard.tsx
@@ -69,16 +69,11 @@ export const ProjectCard = ({
return (
-
(
-
- )}
+
{name}
diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts
index 558dbeab57..b7d6dbd0e3 100644
--- a/frontend/src/interfaces/uiConfig.ts
+++ b/frontend/src/interfaces/uiConfig.ts
@@ -44,7 +44,6 @@ export interface IFlags {
embedProxyFrontend?: boolean;
changeRequests?: boolean;
variantsPerEnvironment?: boolean;
- favorites?: boolean;
networkView?: boolean;
maintenance?: boolean;
}
diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap
index 4540c3dd2f..10007de7d8 100644
--- a/src/lib/__snapshots__/create-config.test.ts.snap
+++ b/src/lib/__snapshots__/create-config.test.ts.snap
@@ -74,7 +74,6 @@ exports[`should create default config 1`] = `
"changeRequests": false,
"embedProxy": true,
"embedProxyFrontend": true,
- "favorites": false,
"maintenance": false,
"maintenanceMode": false,
"networkView": false,
@@ -92,7 +91,6 @@ exports[`should create default config 1`] = `
"changeRequests": false,
"embedProxy": true,
"embedProxyFrontend": true,
- "favorites": false,
"maintenance": false,
"maintenanceMode": false,
"networkView": false,
diff --git a/src/lib/db/feature-strategy-store.ts b/src/lib/db/feature-strategy-store.ts
index 17417f9ba8..c495b4dd29 100644
--- a/src/lib/db/feature-strategy-store.ts
+++ b/src/lib/db/feature-strategy-store.ts
@@ -259,7 +259,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
.modify(FeatureToggleStore.filterByArchived, archived);
let selectColumns = ['features_view.*'] as (string | Raw)[];
- if (userId && this.flagResolver.isEnabled('favorites')) {
+ if (userId) {
query = query.leftJoin(`favorite_features`, function () {
this.on(
'favorite_features.feature',
@@ -460,7 +460,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
'ft.tag_type as tag_type',
] as (string | Raw)[];
- if (userId && this.flagResolver.isEnabled('favorites')) {
+ if (userId) {
query = query.leftJoin(`favorite_features`, function () {
this.on('favorite_features.feature', 'features.name').andOnVal(
'favorite_features.user_id',
diff --git a/src/lib/db/feature-toggle-client-store.ts b/src/lib/db/feature-toggle-client-store.ts
index 8fec32a84c..4359245fb2 100644
--- a/src/lib/db/feature-toggle-client-store.ts
+++ b/src/lib/db/feature-toggle-client-store.ts
@@ -146,7 +146,7 @@ export default class FeatureToggleClientStore
'ft.tag_type as tag_type',
];
- if (userId && this.flagResolver.isEnabled('favorites')) {
+ if (userId) {
query = query.leftJoin(`favorite_features`, function () {
this.on(
'favorite_features.feature',
diff --git a/src/lib/db/project-store.ts b/src/lib/db/project-store.ts
index d49bd08b9f..7467bc715d 100644
--- a/src/lib/db/project-store.ts
+++ b/src/lib/db/project-store.ts
@@ -100,7 +100,7 @@ class ProjectStore implements IProjectStore {
let groupByColumns = ['projects.id'];
- if (userId && this.flagResolver.isEnabled('favorites')) {
+ if (userId) {
projects = projects.leftJoin(`favorite_projects`, function () {
this.on('favorite_projects.project', 'projects.id').andOnVal(
'favorite_projects.user_id',
diff --git a/src/lib/routes/admin-api/index.ts b/src/lib/routes/admin-api/index.ts
index 8e54a8e055..04b479c149 100644
--- a/src/lib/routes/admin-api/index.ts
+++ b/src/lib/routes/admin-api/index.ts
@@ -27,7 +27,6 @@ import PatController from './user/pat';
import { PublicSignupController } from './public-signup';
import InstanceAdminController from './instance-admin';
import FavoritesController from './favorites';
-import { conditionalMiddleware } from '../../middleware';
import MaintenanceController from './maintenance';
class AdminApi extends Controller {
@@ -120,10 +119,7 @@ class AdminApi extends Controller {
);
this.app.use(
`/projects`,
- conditionalMiddleware(
- () => config.flagResolver.isEnabled('favorites'),
- new FavoritesController(config, services).router,
- ),
+ new FavoritesController(config, services).router,
);
this.app.use(
diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts
index b6c9a2f121..483f15bfd1 100644
--- a/src/lib/types/experimental.ts
+++ b/src/lib/types/experimental.ts
@@ -35,10 +35,6 @@ const flags = {
process.env.UNLEASH_EXPERIMENTAL_VARIANTS_PER_ENVIRONMENT,
false,
),
- favorites: parseEnvVarBoolean(
- process.env.UNLEASH_EXPERIMENTAL_FAVORITES,
- false,
- ),
networkView: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_NETWORK_VIEW,
false,
diff --git a/src/server-dev.ts b/src/server-dev.ts
index 1d4bbdf880..24881f79d7 100644
--- a/src/server-dev.ts
+++ b/src/server-dev.ts
@@ -40,7 +40,6 @@ process.nextTick(async () => {
anonymiseEventLog: false,
responseTimeWithAppName: true,
changeRequests: true,
- favorites: true,
variantsPerEnvironment: true,
},
},
diff --git a/src/test/config/test-config.ts b/src/test/config/test-config.ts
index f96f4896be..c3591840c3 100644
--- a/src/test/config/test-config.ts
+++ b/src/test/config/test-config.ts
@@ -29,7 +29,6 @@ export function createTestConfig(config?: IUnleashOptions): IUnleashConfig {
batchMetrics: true,
changeRequests: true,
variantsPerEnvironment: true,
- favorites: true,
},
},
};
diff --git a/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap b/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap
index 90876aec76..c526d268fe 100644
--- a/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap
+++ b/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap
@@ -5333,6 +5333,50 @@ If the provided project does not exist, the list of events will be empty.",
],
},
},
+ "/api/admin/projects/{projectId}/favorites": {
+ "delete": {
+ "operationId": "removeFavoriteProject",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "projectId",
+ "required": true,
+ "schema": {
+ "type": "string",
+ },
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "This response has no body.",
+ },
+ },
+ "tags": [
+ "Features",
+ ],
+ },
+ "post": {
+ "operationId": "addFavoriteProject",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "projectId",
+ "required": true,
+ "schema": {
+ "type": "string",
+ },
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "This response has no body.",
+ },
+ },
+ "tags": [
+ "Features",
+ ],
+ },
+ },
"/api/admin/projects/{projectId}/features": {
"get": {
"operationId": "getFeatures",
@@ -6304,6 +6348,66 @@ If the provided project does not exist, the list of events will be empty.",
],
},
},
+ "/api/admin/projects/{projectId}/features/{featureName}/favorites": {
+ "delete": {
+ "operationId": "removeFavoriteFeature",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "projectId",
+ "required": true,
+ "schema": {
+ "type": "string",
+ },
+ },
+ {
+ "in": "path",
+ "name": "featureName",
+ "required": true,
+ "schema": {
+ "type": "string",
+ },
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "This response has no body.",
+ },
+ },
+ "tags": [
+ "Features",
+ ],
+ },
+ "post": {
+ "operationId": "addFavoriteFeature",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "projectId",
+ "required": true,
+ "schema": {
+ "type": "string",
+ },
+ },
+ {
+ "in": "path",
+ "name": "featureName",
+ "required": true,
+ "schema": {
+ "type": "string",
+ },
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "This response has no body.",
+ },
+ },
+ "tags": [
+ "Features",
+ ],
+ },
+ },
"/api/admin/projects/{projectId}/features/{featureName}/variants": {
"get": {
"operationId": "getFeatureVariants",