1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-12 13:48:35 +02:00

chore: Backport 4.22.3 (#3508)

<!-- Thanks for creating a PR! To make it easier for reviewers and
everyone else to understand what your changes relate to, please add some
relevant content to the headings below. Feel free to ignore or delete
sections that you don't think are relevant. Thank you! ❤️ -->
Backports stickiness fixes 
## About the changes
<!-- Describe the changes introduced. What are they and why are they
being introduced? Feel free to also add screenshots or steps to view the
changes if they're visual. -->

<!-- Does it close an issue? Multiple? -->
Closes #

<!-- (For internal contributors): Does it relate to an issue on public
roadmap? -->
<!--
Relates to [roadmap](https://github.com/orgs/Unleash/projects/10) item:
#
-->

### Important files
<!-- PRs can contain a lot of changes, but not all changes are equally
important. Where should a reviewer start looking to get an overview of
the changes? Are any files particularly important? -->


## Discussion points
<!-- Anything about the PR you'd like to discuss before it gets merged?
Got any questions or doubts? -->

---------

Signed-off-by: andreas-unleash <andreas@getunleash.ai>
Co-authored-by: Gastón Fournier <gaston@getunleash.io>
Co-authored-by: GitHub Actions Bot <>
Co-authored-by: Mateusz Kwasniewski <kwasniewski.mateusz@gmail.com>
This commit is contained in:
andreas-unleash 2023-04-12 16:22:13 +03:00 committed by GitHub
parent 014a8a2280
commit 60a2c1a996
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 81 additions and 62 deletions

View File

@ -15,7 +15,6 @@ describe('notifications', () => {
cy.runBefore(); cy.runBefore();
}); });
// This one is failing on CI: https://github.com/Unleash/unleash/actions/runs/4609305167/jobs/8160244872#step:4:193
it.skip('should create a notification when a feature is created in a project', () => { it.skip('should create a notification when a feature is created in a project', () => {
cy.login_UI(); cy.login_UI();
cy.createUser_API(userName, EDITOR).then(value => { cy.createUser_API(userName, EDITOR).then(value => {
@ -41,7 +40,7 @@ describe('notifications', () => {
cy.get("[data-testid='NOTIFICATIONS_BUTTON']").click(); cy.get("[data-testid='NOTIFICATIONS_BUTTON']").click();
//then //then
// cy.get("[data-testid='UNREAD_NOTIFICATIONS']").should('exist'); cy.get("[data-testid='UNREAD_NOTIFICATIONS']").should('exist');
cy.get("[data-testid='NOTIFICATIONS_LIST']").should( cy.get("[data-testid='NOTIFICATIONS_LIST']").should(
'contain.text', 'contain.text',
`New feature ${featureToggleName}` `New feature ${featureToggleName}`

View File

@ -74,7 +74,7 @@ export const FeatureStrategyCreate = () => {
forceRefreshCache(feature); forceRefreshCache(feature);
ref.current = feature; ref.current = feature;
} }
}, [feature]); }, [feature.name]);
useEffect(() => { useEffect(() => {
if (strategyDefinition) { if (strategyDefinition) {

View File

@ -273,7 +273,13 @@ export const EnvironmentVariantsModal = ({
isChangeRequestConfigured(environment?.name || '') && isChangeRequestConfigured(environment?.name || '') &&
uiConfig.flags.crOnVariants; uiConfig.flags.crOnVariants;
const stickiness = variants[0]?.stickiness || defaultStickiness; const stickiness = useMemo(() => {
if (!loading) {
return variants[0]?.stickiness || defaultStickiness;
}
return '';
}, [loading, defaultStickiness, JSON.stringify(variants[0] ?? {})]);
const stickinessOptions = useMemo( const stickinessOptions = useMemo(
() => [ () => [
'default', 'default',
@ -296,7 +302,7 @@ export const EnvironmentVariantsModal = ({
}; };
const onStickinessChange = (value: string) => { const onStickinessChange = (value: string) => {
updateStickiness(value).catch(console.warn); updateStickiness(value);
}; };
const [error, setError] = useState<string | undefined>(); const [error, setError] = useState<string | undefined>();
@ -308,14 +314,13 @@ export const EnvironmentVariantsModal = ({
}, [apiPayload.error]); }, [apiPayload.error]);
const handleClose = () => { const handleClose = () => {
updateStickiness(defaultStickiness).then(); updateStickiness(defaultStickiness);
setOpen(false); setOpen(false);
}; };
if (loading || stickiness === '') { if (loading || stickiness === '') {
return <Loader />; return <Loader />;
} }
return ( return (
<SidebarModal open={open} onClose={handleClose} label=""> <SidebarModal open={open} onClose={handleClose} label="">
<FormTemplate <FormTemplate

View File

@ -12,10 +12,10 @@ import {
parseParameterString, parseParameterString,
} from 'utils/parseParameter'; } from 'utils/parseParameter';
import { StickinessSelect } from './StickinessSelect/StickinessSelect'; import { StickinessSelect } from './StickinessSelect/StickinessSelect';
import { useOptionalPathParam } from 'hooks/useOptionalPathParam';
import { useDefaultProjectSettings } from 'hooks/useDefaultProjectSettings'; import { useDefaultProjectSettings } from 'hooks/useDefaultProjectSettings';
import Loader from '../../../common/Loader/Loader'; import Loader from '../../../common/Loader/Loader';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
interface IFlexibleStrategyProps { interface IFlexibleStrategyProps {
parameters: IFeatureStrategyParameters; parameters: IFeatureStrategyParameters;
@ -29,7 +29,7 @@ const FlexibleStrategy = ({
parameters, parameters,
editable = true, editable = true,
}: IFlexibleStrategyProps) => { }: IFlexibleStrategyProps) => {
const projectId = useOptionalPathParam('projectId'); const projectId = useRequiredPathParam('projectId');
const { defaultStickiness, loading } = useDefaultProjectSettings(projectId); const { defaultStickiness, loading } = useDefaultProjectSettings(projectId);
const onUpdate = (field: string) => (newValue: string) => { const onUpdate = (field: string) => (newValue: string) => {

View File

@ -41,7 +41,6 @@ export const StickinessSelect = ({
); );
const stickinessOptions = resolveStickinessOptions(); const stickinessOptions = resolveStickinessOptions();
return ( return (
<Select <Select
id="stickiness-select" id="stickiness-select"

View File

@ -13,6 +13,7 @@ const fallbackProject: IProject = {
description: 'Default', description: 'Default',
favorite: false, favorite: false,
mode: 'open', mode: 'open',
defaultStickiness: 'default',
stats: { stats: {
archivedCurrentWindow: 0, archivedCurrentWindow: 0,
archivedPastWindow: 0, archivedPastWindow: 0,

View File

@ -1,57 +1,19 @@
import useUiConfig from './api/getters/useUiConfig/useUiConfig'; import useUiConfig from './api/getters/useUiConfig/useUiConfig';
import { SWRConfiguration } from 'swr'; import useProject from './api/getters/useProject/useProject';
import { useCallback } from 'react';
import handleErrorResponses from './api/getters/httpErrorResponseHandler';
import { useConditionalSWR } from './api/getters/useConditionalSWR/useConditionalSWR';
import { ProjectMode } from 'component/project/Project/hooks/useProjectForm';
import { formatApiPath } from 'utils/formatPath';
export interface ISettingsResponse {
defaultStickiness?: string;
mode?: ProjectMode;
}
const DEFAULT_STICKINESS = 'default'; const DEFAULT_STICKINESS = 'default';
export const useDefaultProjectSettings = ( export const useDefaultProjectSettings = (projectId: string) => {
projectId?: string,
options?: SWRConfiguration
) => {
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();
const PATH = `api/admin/projects/${projectId}/settings`;
const { projectScopedStickiness } = uiConfig.flags; const { projectScopedStickiness } = uiConfig.flags;
const { data, isLoading, error, mutate } = const { project, loading, error } = useProject(projectId);
useConditionalSWR<ISettingsResponse>(
Boolean(projectId) && Boolean(projectScopedStickiness),
{},
['useDefaultProjectSettings', PATH],
() => fetcher(formatApiPath(PATH)),
options
);
const defaultStickiness = (): string => {
if (!isLoading) {
if (data?.defaultStickiness) {
return data?.defaultStickiness;
}
return DEFAULT_STICKINESS;
}
return '';
};
const refetch = useCallback(() => {
mutate().catch(console.warn);
}, [mutate]);
return { return {
defaultStickiness: defaultStickiness(), defaultStickiness: Boolean(projectScopedStickiness)
refetch, ? project.defaultStickiness
loading: isLoading, : DEFAULT_STICKINESS,
mode: project.mode,
loading: loading,
error, error,
}; };
}; };
const fetcher = (path: string) => {
return fetch(path)
.then(handleErrorResponses('Project stickiness data'))
.then(res => res.json());
};

View File

@ -24,6 +24,7 @@ export interface IProject {
favorite: boolean; favorite: boolean;
features: IFeatureToggleListItem[]; features: IFeatureToggleListItem[];
mode: 'open' | 'protected'; mode: 'open' | 'protected';
defaultStickiness: string;
} }
export interface IProjectHealthReport extends IProject { export interface IProjectHealthReport extends IProject {

View File

@ -33,7 +33,7 @@ const COLUMNS = [
'updated_at', 'updated_at',
]; ];
const TABLE = 'projects'; const TABLE = 'projects';
const SETTINGS_COLUMNS = ['project_mode']; const SETTINGS_COLUMNS = ['project_mode', 'default_stickiness'];
const SETTINGS_TABLE = 'project_settings'; const SETTINGS_TABLE = 'project_settings';
export interface IEnvironmentProjectLink { export interface IEnvironmentProjectLink {
@ -531,6 +531,7 @@ class ProjectStore implements IProjectStore {
health: row.health ?? 100, health: row.health ?? 100,
updatedAt: row.updated_at || new Date(), updatedAt: row.updated_at || new Date(),
mode: row.project_mode || 'open', mode: row.project_mode || 'open',
defaultStickiness: row.default_stickiness || 'default',
}; };
} }
} }

View File

@ -798,13 +798,12 @@ export default class ProjectService {
: Promise.resolve(false), : Promise.resolve(false),
this.projectStatsStore.getProjectStats(projectId), this.projectStatsStore.getProjectStats(projectId),
]); ]);
return { return {
stats: projectStats, stats: projectStats,
name: project.name, name: project.name,
description: project.description, description: project.description,
mode: project.mode, mode: project.mode,
defaultStickiness: project.defaultStickiness || 'default', defaultStickiness: project.defaultStickiness,
health: project.health || 0, health: project.health || 0,
favorite: favorite, favorite: favorite,
updatedAt: project.updatedAt, updatedAt: project.updatedAt,

View File

@ -372,7 +372,7 @@ export interface IProject {
updatedAt?: Date; updatedAt?: Date;
changeRequestsEnabled?: boolean; changeRequestsEnabled?: boolean;
mode: ProjectMode; mode: ProjectMode;
defaultStickiness?: string; defaultStickiness: string;
} }
export interface ICustomRole { export interface ICustomRole {

View File

@ -525,7 +525,12 @@ describe('Interacting with features using project IDs that belong to other proje
rootRole: RoleName.ADMIN, rootRole: RoleName.ADMIN,
}); });
await app.services.projectService.createProject( await app.services.projectService.createProject(
{ name: otherProject, id: otherProject, mode: 'open' }, {
name: otherProject,
id: otherProject,
mode: 'open',
defaultStickiness: 'clientId',
},
dummyAdmin, dummyAdmin,
); );

View File

@ -101,7 +101,7 @@ const createProject = async (id: string, name: string): Promise<void> => {
email: `${randomId()}@example.com`, email: `${randomId()}@example.com`,
}); });
await app.services.projectService.createProject( await app.services.projectService.createProject(
{ id, name, mode: 'open' }, { id, name, mode: 'open', defaultStickiness: 'default' },
user, user,
); );
}; };

View File

@ -43,6 +43,7 @@ beforeAll(async () => {
name: 'Test Project', name: 'Test Project',
description: 'Fancy', description: 'Fancy',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const user = await stores.userStore.insert({ const user = await stores.userStore.insert({
name: 'Some Name', name: 'Some Name',

View File

@ -107,6 +107,7 @@ test('should list all projects', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'default',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -121,6 +122,7 @@ test('should create new project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'protected' as const, mode: 'protected' as const,
defaultStickiness: 'default',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -138,6 +140,7 @@ test('should delete project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'default',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -156,12 +159,14 @@ test('should not be able to delete project with toggles', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
await stores.featureToggleStore.create(project.id, { await stores.featureToggleStore.create(project.id, {
name: 'test-project-delete', name: 'test-project-delete',
project: project.id, project: project.id,
enabled: false, enabled: false,
defaultStickiness: 'default',
}); });
try { try {
@ -192,6 +197,7 @@ test('should not be able to create existing project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'default',
}; };
try { try {
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -223,6 +229,7 @@ test('should update project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'default',
}; };
const updatedProject = { const updatedProject = {
@ -230,6 +237,7 @@ test('should update project', async () => {
name: 'New name', name: 'New name',
description: 'Blah longer desc', description: 'Blah longer desc',
mode: 'protected' as const, mode: 'protected' as const,
defaultStickiness: 'userId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -240,6 +248,7 @@ test('should update project', async () => {
expect(updatedProject.name).toBe(readProject.name); expect(updatedProject.name).toBe(readProject.name);
expect(updatedProject.description).toBe(readProject.description); expect(updatedProject.description).toBe(readProject.description);
expect(updatedProject.mode).toBe('protected'); expect(updatedProject.mode).toBe('protected');
expect(updatedProject.defaultStickiness).toBe('userId');
}); });
test('should update project without existing settings', async () => { test('should update project without existing settings', async () => {
@ -248,6 +257,7 @@ test('should update project without existing settings', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'default',
}; };
const updatedProject = { const updatedProject = {
@ -255,6 +265,7 @@ test('should update project without existing settings', async () => {
name: 'New name', name: 'New name',
description: 'Blah longer desc', description: 'Blah longer desc',
mode: 'protected' as const, mode: 'protected' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -269,6 +280,7 @@ test('should update project without existing settings', async () => {
expect(updatedProject.name).toBe(readProject.name); expect(updatedProject.name).toBe(readProject.name);
expect(updatedProject.description).toBe(readProject.description); expect(updatedProject.description).toBe(readProject.description);
expect(updatedProject.mode).toBe('protected'); expect(updatedProject.mode).toBe('protected');
expect(updatedProject.defaultStickiness).toBe('clientId');
}); });
test('should give error when getting unknown project', async () => { test('should give error when getting unknown project', async () => {
@ -285,6 +297,7 @@ test('should get list of users with access to project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
const { users } = await projectService.getAccessToProject(project.id); const { users } = await projectService.getAccessToProject(project.id);
@ -307,6 +320,7 @@ test('should add a member user to the project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -363,6 +377,7 @@ test('should add admin users to the project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -410,6 +425,7 @@ test('add user should fail if user already have access', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -445,6 +461,7 @@ test('should remove user from the project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -480,6 +497,7 @@ test('should not remove user from the project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -504,6 +522,7 @@ test('should not change project if feature toggle project does not match current
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const toggle = { name: 'test-toggle' }; const toggle = { name: 'test-toggle' };
@ -531,6 +550,7 @@ test('should return 404 if no project is found with the project id', async () =>
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const toggle = { name: 'test-toggle-2' }; const toggle = { name: 'test-toggle-2' };
@ -556,6 +576,7 @@ test('should fail if user is not authorized', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const projectDestination = { const projectDestination = {
@ -563,6 +584,7 @@ test('should fail if user is not authorized', async () => {
name: 'New project 2', name: 'New project 2',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const toggle = { name: 'test-toggle-3' }; const toggle = { name: 'test-toggle-3' };
@ -594,11 +616,13 @@ test('should change project when checks pass', async () => {
id: randomId(), id: randomId(),
name: randomId(), name: randomId(),
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const projectB = { const projectB = {
id: randomId(), id: randomId(),
name: randomId(), name: randomId(),
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const toggle = { name: randomId() }; const toggle = { name: randomId() };
@ -623,11 +647,13 @@ test('changing project should emit event even if user does not have a username s
id: randomId(), id: randomId(),
name: randomId(), name: randomId(),
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'default',
}; };
const projectB = { const projectB = {
id: randomId(), id: randomId(),
name: randomId(), name: randomId(),
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const toggle = { name: randomId() }; const toggle = { name: randomId() };
await projectService.createProject(projectA, user); await projectService.createProject(projectA, user);
@ -649,11 +675,13 @@ test('should require equal project environments to move features', async () => {
id: randomId(), id: randomId(),
name: randomId(), name: randomId(),
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const projectB = { const projectB = {
id: randomId(), id: randomId(),
name: randomId(), name: randomId(),
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const environment = { name: randomId(), type: 'production' }; const environment = { name: randomId(), type: 'production' };
const toggle = { name: randomId() }; const toggle = { name: randomId() };
@ -683,6 +711,7 @@ test('A newly created project only gets connected to enabled environments', asyn
name: 'New environment project', name: 'New environment project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const enabledEnv = 'connection_test'; const enabledEnv = 'connection_test';
await db.stores.environmentStore.create({ await db.stores.environmentStore.create({
@ -710,6 +739,7 @@ test('should have environments sorted in order', async () => {
name: 'Environment testing project', name: 'Environment testing project',
description: '', description: '',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const first = 'test'; const first = 'test';
const second = 'abc'; const second = 'abc';
@ -749,6 +779,7 @@ test('should add a user to the project with a custom role', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -800,6 +831,7 @@ test('should delete role entries when deleting project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -852,6 +884,7 @@ test('should change a users role in the project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -919,6 +952,7 @@ test('should update role for user on project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -957,6 +991,7 @@ test('should able to assign role without existing members', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -1000,6 +1035,7 @@ test('should not update role for user on project when she is the owner', async (
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -1034,6 +1070,7 @@ test('Should allow bulk update of group permissions', async () => {
id: 'bulk-update-project', id: 'bulk-update-project',
name: 'bulk-update-project', name: 'bulk-update-project',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user.id); await projectService.createProject(project, user.id);
const groupStore = stores.groupStore; const groupStore = stores.groupStore;
@ -1111,6 +1148,7 @@ test('Should allow bulk update of only groups', async () => {
id: 'bulk-update-project-only', id: 'bulk-update-project-only',
name: 'bulk-update-project-only', name: 'bulk-update-project-only',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const groupStore = stores.groupStore; const groupStore = stores.groupStore;
@ -1152,6 +1190,7 @@ test('should only count active feature toggles for project', async () => {
name: 'New project', name: 'New project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -1180,6 +1219,7 @@ test('should list projects with all features archived', async () => {
name: 'Listed project', name: 'Listed project',
description: 'Blah', description: 'Blah',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user); await projectService.createProject(project, user);
@ -1216,6 +1256,7 @@ test('should calculate average time to production', async () => {
id: 'average-time-to-prod', id: 'average-time-to-prod',
name: 'average-time-to-prod', name: 'average-time-to-prod',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user.id); await projectService.createProject(project, user.id);
@ -1274,6 +1315,7 @@ test('should calculate average time to production ignoring some items', async ()
id: 'average-time-to-prod-corner-cases', id: 'average-time-to-prod-corner-cases',
name: 'average-time-to-prod', name: 'average-time-to-prod',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
const makeEvent = (featureName: string) => ({ const makeEvent = (featureName: string) => ({
enabled: true, enabled: true,
@ -1362,6 +1404,7 @@ test('should get correct amount of features created in current and past window',
id: 'features-created', id: 'features-created',
name: 'features-created', name: 'features-created',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user.id); await projectService.createProject(project, user.id);
@ -1398,6 +1441,7 @@ test('should get correct amount of features archived in current and past window'
id: 'features-archived', id: 'features-archived',
name: 'features-archived', name: 'features-archived',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'clientId',
}; };
await projectService.createProject(project, user.id); await projectService.createProject(project, user.id);
@ -1448,6 +1492,7 @@ test('should get correct amount of project members for current and past window',
id: 'features-members', id: 'features-members',
name: 'features-members', name: 'features-members',
mode: 'open' as const, mode: 'open' as const,
defaultStickiness: 'default',
}; };
await projectService.createProject(project, user.id); await projectService.createProject(project, user.id);

View File

@ -55,6 +55,7 @@ export default class FakeProjectStore implements IProjectStore {
health: 100, health: 100,
createdAt: new Date(), createdAt: new Date(),
mode: 'open', mode: 'open',
defaultStickiness: 'default',
}; };
this.projects.push(newProj); this.projects.push(newProj);
return newProj; return newProj;