1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-31 00:16:47 +01:00
unleash.unleash/src/lib/features/feature-toggle/createFeatureToggleService.ts

179 lines
6.9 KiB
TypeScript
Raw Normal View History

2023-02-16 08:08:51 +01:00
import {
AccessService,
FeatureToggleService,
GroupService,
} from '../../services';
import FeatureStrategiesStore from '../../db/feature-strategy-store';
import FeatureToggleStore from '../../db/feature-toggle-store';
import FeatureToggleClientStore from '../../db/feature-toggle-client-store';
import ProjectStore from '../../db/project-store';
import FeatureTagStore from '../../db/feature-tag-store';
import { FeatureEnvironmentStore } from '../../db/feature-environment-store';
import ContextFieldStore from '../../db/context-field-store';
import GroupStore from '../../db/group-store';
import { AccountStore } from '../../db/account-store';
import { AccessStore } from '../../db/access-store';
import RoleStore from '../../db/role-store';
import EnvironmentStore from '../../db/environment-store';
import { Db } from '../../db/db';
2023-03-02 09:52:19 +01:00
import { IUnleashConfig } from '../../types';
import FakeEventStore from '../../../test/fixtures/fake-event-store';
import FakeFeatureStrategiesStore from '../../../test/fixtures/fake-feature-strategies-store';
import FakeFeatureToggleStore from '../../../test/fixtures/fake-feature-toggle-store';
import FakeFeatureToggleClientStore from '../../../test/fixtures/fake-feature-toggle-client-store';
import FakeProjectStore from '../../../test/fixtures/fake-project-store';
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
import FakeFeatureEnvironmentStore from '../../../test/fixtures/fake-feature-environment-store';
import FakeContextFieldStore from '../../../test/fixtures/fake-context-field-store';
import FakeGroupStore from '../../../test/fixtures/fake-group-store';
import { FakeAccountStore } from '../../../test/fixtures/fake-account-store';
import FakeAccessStore from '../../../test/fixtures/fake-access-store';
import FakeRoleStore from '../../../test/fixtures/fake-role-store';
import FakeEnvironmentStore from '../../../test/fixtures/fake-environment-store';
2023-03-02 09:52:19 +01:00
import EventStore from '../../db/event-store';
import {
createChangeRequestAccessReadModel,
createFakeChangeRequestAccessService,
} from '../change-request-access-service/createChangeRequestAccessReadModel';
import {
createFakeSegmentService,
createSegmentService,
} from '../segment/createSegmentService';
import StrategyStore from '../../db/strategy-store';
import FakeStrategiesStore from '../../../test/fixtures/fake-strategies-store';
import {
createFakeprivateProjectChecker,
createPrivateProjectChecker,
} from '../private-project/createPrivateProjectChecker';
2023-02-16 08:08:51 +01:00
export const createFeatureToggleService = (
db: Db,
config: IUnleashConfig,
): FeatureToggleService => {
const { getLogger, eventBus, flagResolver } = config;
const featureStrategiesStore = new FeatureStrategiesStore(
db,
eventBus,
getLogger,
flagResolver,
);
const featureToggleStore = new FeatureToggleStore(db, eventBus, getLogger);
const featureToggleClientStore = new FeatureToggleClientStore(
db,
eventBus,
getLogger,
flagResolver,
2023-02-16 08:08:51 +01:00
);
const projectStore = new ProjectStore(
db,
eventBus,
getLogger,
flagResolver,
);
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
const featureEnvironmentStore = new FeatureEnvironmentStore(
db,
eventBus,
getLogger,
);
const contextFieldStore = new ContextFieldStore(
db,
getLogger,
flagResolver,
);
2023-02-16 08:08:51 +01:00
const groupStore = new GroupStore(db);
const strategyStore = new StrategyStore(db, getLogger);
2023-02-16 08:08:51 +01:00
const accountStore = new AccountStore(db, getLogger);
const accessStore = new AccessStore(db, eventBus, getLogger);
const roleStore = new RoleStore(db, eventBus, getLogger);
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
2023-03-02 09:52:19 +01:00
const eventStore = new EventStore(db, getLogger);
2023-02-16 08:08:51 +01:00
const groupService = new GroupService(
{ groupStore, eventStore, accountStore },
{ getLogger },
);
const accessService = new AccessService(
{ accessStore, accountStore, roleStore, environmentStore, groupStore },
feat: custom root roles (#3975) ## About the changes Implements custom root roles, encompassing a lot of different areas of the project, and slightly refactoring the current roles logic. It includes quite a clean up. This feature itself is behind a flag: `customRootRoles` This feature covers root roles in: - Users; - Service Accounts; - Groups; Apologies in advance. I may have gotten a bit carried away 🙈 ### Roles We now have a new admin tab called "Roles" where we can see all root roles and manage custom ones. We are not allowed to edit or remove *predefined* roles. ![image](https://github.com/Unleash/unleash/assets/14320932/1ad8695c-8c3f-440d-ac32-39746720d588) This meant slightly pushing away the existing roles to `project-roles` instead. One idea we want to explore in the future is to unify both types of roles in the UI instead of having 2 separate tabs. This includes modernizing project roles to fit more into our current design and decisions. Hovering the permissions cell expands detailed information about the role: ![image](https://github.com/Unleash/unleash/assets/14320932/81c4aae7-8b4d-4cb4-92d1-8f1bc3ef1f2a) ### Create and edit role Here's how the role form looks like (create / edit): ![image](https://github.com/Unleash/unleash/assets/14320932/85baec29-bb10-48c5-a207-b3e9a8de838a) Here I categorized permissions so it's easier to visualize and manage from a UX perspective. I'm using the same endpoint as before. I tried to unify the logic and get rid of the `projectRole` specific hooks. What distinguishes custom root roles from custom project roles is the extra `root-custom` type we see on the payload. By default we assume `custom` (custom project role) instead, which should help in terms of backwards compatibility. ### Delete role When we delete a custom role we try to help the end user make an informed decision by listing all the entities which currently use this custom root role: ![image](https://github.com/Unleash/unleash/assets/14320932/352ed529-76be-47a8-88da-5e924fb191d4) ~~As mentioned in the screenshot, when deleting a custom role, we demote all entities associated with it to the predefined `Viewer` role.~~ **EDIT**: Apparently we currently block this from the API (access-service deleteRole) with a message: ![image](https://github.com/Unleash/unleash/assets/14320932/82a8e50f-8dc5-4c18-a2ba-54e2ae91b91c) What should the correct behavior be? ### Role selector I added a new easy-to-use role selector component that is present in: - Users ![image](https://github.com/Unleash/unleash/assets/14320932/76953139-7fb6-437e-b3fa-ace1d9187674) - Service Accounts ![image](https://github.com/Unleash/unleash/assets/14320932/2b80bd55-9abb-4883-b715-15650ae752ea) - Groups ![image](https://github.com/Unleash/unleash/assets/14320932/ab438f7c-2245-4779-b157-2da1689fe402) ### Role description I also added a new role description component that you can see below the dropdown in the selector component, but it's also used to better describe each role in the respective tables: ![image](https://github.com/Unleash/unleash/assets/14320932/a3eecac1-2a34-4500-a68c-e3f62ebfa782) I'm not listing all the permissions of predefined roles. Those simply show the description in the tooltip: ![image](https://github.com/Unleash/unleash/assets/14320932/7e5b2948-45f0-4472-8311-bf533409ba6c) ### Role badge Groups is a bit different, since it uses a list of cards, so I added yet another component - Role badge: ![image](https://github.com/Unleash/unleash/assets/14320932/1d62c3db-072a-4c97-b86f-1d8ebdd3523e) I'm using this same component on the profile tab: ![image](https://github.com/Unleash/unleash/assets/14320932/214272db-a828-444e-8846-4f39b9456bc6) ## Discussion points - Are we being defensive enough with the use of the flag? Should we cover more? - Are we breaking backwards compatibility in any way? - What should we do when removing a role? Block or demote? - Maybe some existing permission-related issues will surface with this change: Are we being specific enough with our permissions? A lot of places are simply checking for `ADMIN`; - We may want to get rid of the API roles coupling we have with the users and SAs and instead use the new hooks (e.g. `useRoles`) explicitly; - We should update the docs; - Maybe we could allow the user to add a custom role directly from the role selector component; --------- Co-authored-by: Gastón Fournier <gaston@getunleash.io>
2023-06-14 15:40:40 +02:00
{ getLogger, flagResolver },
2023-02-16 08:08:51 +01:00
groupService,
);
const segmentService = createSegmentService(db, config);
const changeRequestAccessReadModel = createChangeRequestAccessReadModel(
db,
config,
);
const privateProjectChecker = createPrivateProjectChecker(db, config);
2023-02-16 08:08:51 +01:00
const featureToggleService = new FeatureToggleService(
{
featureStrategiesStore,
featureToggleStore,
featureToggleClientStore,
projectStore,
eventStore,
featureTagStore,
featureEnvironmentStore,
contextFieldStore,
strategyStore,
2023-02-16 08:08:51 +01:00
},
{ getLogger, flagResolver },
segmentService,
accessService,
changeRequestAccessReadModel,
privateProjectChecker,
2023-02-16 08:08:51 +01:00
);
return featureToggleService;
};
export const createFakeFeatureToggleService = (
config: IUnleashConfig,
): FeatureToggleService => {
const { getLogger, flagResolver } = config;
const eventStore = new FakeEventStore();
const strategyStore = new FakeStrategiesStore();
2023-02-16 08:08:51 +01:00
const featureStrategiesStore = new FakeFeatureStrategiesStore();
const featureToggleStore = new FakeFeatureToggleStore();
const featureToggleClientStore = new FakeFeatureToggleClientStore();
const projectStore = new FakeProjectStore();
const featureTagStore = new FakeFeatureTagStore();
const featureEnvironmentStore = new FakeFeatureEnvironmentStore();
const contextFieldStore = new FakeContextFieldStore();
const groupStore = new FakeGroupStore();
const accountStore = new FakeAccountStore();
const accessStore = new FakeAccessStore();
const roleStore = new FakeRoleStore();
const environmentStore = new FakeEnvironmentStore();
const groupService = new GroupService(
{ groupStore, eventStore, accountStore },
{ getLogger },
);
const accessService = new AccessService(
{ accessStore, accountStore, roleStore, environmentStore, groupStore },
feat: custom root roles (#3975) ## About the changes Implements custom root roles, encompassing a lot of different areas of the project, and slightly refactoring the current roles logic. It includes quite a clean up. This feature itself is behind a flag: `customRootRoles` This feature covers root roles in: - Users; - Service Accounts; - Groups; Apologies in advance. I may have gotten a bit carried away 🙈 ### Roles We now have a new admin tab called "Roles" where we can see all root roles and manage custom ones. We are not allowed to edit or remove *predefined* roles. ![image](https://github.com/Unleash/unleash/assets/14320932/1ad8695c-8c3f-440d-ac32-39746720d588) This meant slightly pushing away the existing roles to `project-roles` instead. One idea we want to explore in the future is to unify both types of roles in the UI instead of having 2 separate tabs. This includes modernizing project roles to fit more into our current design and decisions. Hovering the permissions cell expands detailed information about the role: ![image](https://github.com/Unleash/unleash/assets/14320932/81c4aae7-8b4d-4cb4-92d1-8f1bc3ef1f2a) ### Create and edit role Here's how the role form looks like (create / edit): ![image](https://github.com/Unleash/unleash/assets/14320932/85baec29-bb10-48c5-a207-b3e9a8de838a) Here I categorized permissions so it's easier to visualize and manage from a UX perspective. I'm using the same endpoint as before. I tried to unify the logic and get rid of the `projectRole` specific hooks. What distinguishes custom root roles from custom project roles is the extra `root-custom` type we see on the payload. By default we assume `custom` (custom project role) instead, which should help in terms of backwards compatibility. ### Delete role When we delete a custom role we try to help the end user make an informed decision by listing all the entities which currently use this custom root role: ![image](https://github.com/Unleash/unleash/assets/14320932/352ed529-76be-47a8-88da-5e924fb191d4) ~~As mentioned in the screenshot, when deleting a custom role, we demote all entities associated with it to the predefined `Viewer` role.~~ **EDIT**: Apparently we currently block this from the API (access-service deleteRole) with a message: ![image](https://github.com/Unleash/unleash/assets/14320932/82a8e50f-8dc5-4c18-a2ba-54e2ae91b91c) What should the correct behavior be? ### Role selector I added a new easy-to-use role selector component that is present in: - Users ![image](https://github.com/Unleash/unleash/assets/14320932/76953139-7fb6-437e-b3fa-ace1d9187674) - Service Accounts ![image](https://github.com/Unleash/unleash/assets/14320932/2b80bd55-9abb-4883-b715-15650ae752ea) - Groups ![image](https://github.com/Unleash/unleash/assets/14320932/ab438f7c-2245-4779-b157-2da1689fe402) ### Role description I also added a new role description component that you can see below the dropdown in the selector component, but it's also used to better describe each role in the respective tables: ![image](https://github.com/Unleash/unleash/assets/14320932/a3eecac1-2a34-4500-a68c-e3f62ebfa782) I'm not listing all the permissions of predefined roles. Those simply show the description in the tooltip: ![image](https://github.com/Unleash/unleash/assets/14320932/7e5b2948-45f0-4472-8311-bf533409ba6c) ### Role badge Groups is a bit different, since it uses a list of cards, so I added yet another component - Role badge: ![image](https://github.com/Unleash/unleash/assets/14320932/1d62c3db-072a-4c97-b86f-1d8ebdd3523e) I'm using this same component on the profile tab: ![image](https://github.com/Unleash/unleash/assets/14320932/214272db-a828-444e-8846-4f39b9456bc6) ## Discussion points - Are we being defensive enough with the use of the flag? Should we cover more? - Are we breaking backwards compatibility in any way? - What should we do when removing a role? Block or demote? - Maybe some existing permission-related issues will surface with this change: Are we being specific enough with our permissions? A lot of places are simply checking for `ADMIN`; - We may want to get rid of the API roles coupling we have with the users and SAs and instead use the new hooks (e.g. `useRoles`) explicitly; - We should update the docs; - Maybe we could allow the user to add a custom role directly from the role selector component; --------- Co-authored-by: Gastón Fournier <gaston@getunleash.io>
2023-06-14 15:40:40 +02:00
{ getLogger, flagResolver },
2023-02-16 08:08:51 +01:00
groupService,
);
const segmentService = createFakeSegmentService(config);
const changeRequestAccessReadModel = createFakeChangeRequestAccessService();
const fakeprivateProjectChecker = createFakeprivateProjectChecker();
2023-02-16 08:08:51 +01:00
const featureToggleService = new FeatureToggleService(
{
featureStrategiesStore,
featureToggleStore,
featureToggleClientStore,
projectStore,
eventStore,
featureTagStore,
featureEnvironmentStore,
contextFieldStore,
strategyStore,
2023-02-16 08:08:51 +01:00
},
{ getLogger, flagResolver },
segmentService,
accessService,
changeRequestAccessReadModel,
fakeprivateProjectChecker,
2023-02-16 08:08:51 +01:00
);
return featureToggleService;
};