mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-26 13:48:33 +02:00
Add suggest-change-store.ts and db migration (#2201)
* Add suggest-change-store.ts and db migration * Add suggest-change-store.ts and db migration * change payload and event data type * Update src/lib/db/suggest-change-store.ts Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com> * split to 3 tables, create event on every change * split to 3 tables, create event on every change * Move service to enterprise PR Comments * PR Comments * replacy createdBy string with User * replace createdBy string with User * added event to docs * return entire changeset after adding a change * bug fix * bug fix * move add change return to service layer * PR comments * added user id to user objects * added user id to user objects * added user id to user objects * bug fix * Rework * Remove event and fix queries * Update snapshot * Remove console logs * Fix Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com> Co-authored-by: sjaanus <sellinjaanus@gmail.com>
This commit is contained in:
parent
8270166286
commit
85631b9951
@ -32,6 +32,7 @@ import SegmentStore from './segment-store';
|
||||
import GroupStore from './group-store';
|
||||
import PatStore from './pat-store';
|
||||
import { PublicSignupTokenStore } from './public-signup-token-store';
|
||||
import { SuggestChangeStore } from './suggest-change-store';
|
||||
|
||||
export const createStores = (
|
||||
config: IUnleashConfig,
|
||||
@ -92,6 +93,7 @@ export const createStores = (
|
||||
getLogger,
|
||||
),
|
||||
patStore: new PatStore(db, getLogger),
|
||||
suggestChangeStore: new SuggestChangeStore(db, eventBus, getLogger),
|
||||
};
|
||||
};
|
||||
|
||||
|
244
src/lib/db/suggest-change-store.ts
Normal file
244
src/lib/db/suggest-change-store.ts
Normal file
@ -0,0 +1,244 @@
|
||||
import { ISuggestChangeStore } from '../types/stores/suggest-change-store';
|
||||
import { Logger, LogProvider } from '../logger';
|
||||
import EventEmitter from 'events';
|
||||
import { Knex } from 'knex';
|
||||
import { PartialSome } from '../types/partial';
|
||||
import {
|
||||
ISuggestChange,
|
||||
ISuggestChangeset,
|
||||
SuggestChangeAction,
|
||||
} from '../types/model';
|
||||
import User from '../types/user';
|
||||
|
||||
const T = {
|
||||
SUGGEST_CHANGE: 'suggest_change',
|
||||
SUGGEST_CHANGE_SET: 'suggest_change_set',
|
||||
};
|
||||
|
||||
interface ISuggestChangesetInsert {
|
||||
id: number;
|
||||
environment: string;
|
||||
state?: string;
|
||||
project?: string;
|
||||
created_by?: number;
|
||||
created_at?: Date;
|
||||
}
|
||||
|
||||
interface ISuggestChangeInsert {
|
||||
id: number;
|
||||
action: SuggestChangeAction;
|
||||
feature: string;
|
||||
payload?: unknown;
|
||||
created_by?: number;
|
||||
created_at?: Date;
|
||||
}
|
||||
|
||||
interface ISuggestChangesetRow extends ISuggestChangesetInsert {
|
||||
changes?: ISuggestChange[];
|
||||
}
|
||||
|
||||
const suggestChangeRowReducer = (acc, suggestChangeRow) => {
|
||||
const {
|
||||
changeId,
|
||||
changeAction,
|
||||
changePayload,
|
||||
changeFeature,
|
||||
changeCreatedByUsername,
|
||||
changeCreatedByAvatar,
|
||||
changeCreatedAt,
|
||||
changeCreatedBy,
|
||||
...suggestChangeSet
|
||||
} = suggestChangeRow;
|
||||
if (!acc[suggestChangeRow.id]) {
|
||||
acc[suggestChangeRow.id] = {
|
||||
id: suggestChangeSet.id,
|
||||
environment: suggestChangeSet.environment,
|
||||
state: suggestChangeSet.state,
|
||||
project: suggestChangeSet.project,
|
||||
createdBy: {
|
||||
id: suggestChangeSet.created_by,
|
||||
username: suggestChangeSet.changeSetUsername,
|
||||
imageUrl: suggestChangeSet.changeSetAvatar,
|
||||
},
|
||||
createdAt: suggestChangeSet.created_at,
|
||||
changes: [],
|
||||
};
|
||||
}
|
||||
const currentSuggestChangeSet = acc[suggestChangeSet.id];
|
||||
|
||||
if (changeId) {
|
||||
currentSuggestChangeSet.changes.push({
|
||||
id: changeId,
|
||||
feature: changeFeature,
|
||||
action: changeAction,
|
||||
payload: changePayload,
|
||||
createdAt: changeCreatedAt,
|
||||
createdBy: {
|
||||
id: changeCreatedBy,
|
||||
username: changeCreatedByUsername,
|
||||
imageUrl: changeCreatedByAvatar,
|
||||
},
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
};
|
||||
|
||||
export class SuggestChangeStore implements ISuggestChangeStore {
|
||||
private logger: Logger;
|
||||
|
||||
private eventBus: EventEmitter;
|
||||
|
||||
private db: Knex;
|
||||
|
||||
constructor(db: Knex, eventBus: EventEmitter, getLogger: LogProvider) {
|
||||
this.db = db;
|
||||
this.eventBus = eventBus;
|
||||
this.logger = getLogger('lib/db/suggest-change-store.ts');
|
||||
}
|
||||
|
||||
private buildSuggestChangeSetChangesQuery = () => {
|
||||
return this.db<ISuggestChangesetRow>(
|
||||
`${T.SUGGEST_CHANGE_SET} as changeSet`,
|
||||
)
|
||||
.leftJoin(
|
||||
`users as changeSetUser`,
|
||||
'changeSet.created_by',
|
||||
'changeSetUser.id',
|
||||
)
|
||||
.leftJoin(`projects`, 'projects.id', 'changeSet.project')
|
||||
.leftJoin(
|
||||
`${T.SUGGEST_CHANGE} as change`,
|
||||
'changeSet.id',
|
||||
'change.suggest_change_set_id',
|
||||
)
|
||||
.leftJoin(
|
||||
`users as changeUser`,
|
||||
'change.created_by',
|
||||
'changeUser.id',
|
||||
)
|
||||
.select(
|
||||
'changeSet.environment',
|
||||
'projects.name as project',
|
||||
'changeSet.created_at',
|
||||
'changeSet.created_by',
|
||||
'changeSetUser.username as changeSetUsername',
|
||||
'changeSetUser.image_url as changeSetAvatar',
|
||||
'change.id as changeId',
|
||||
'change.feature as changeFeature',
|
||||
'change.action as changeAction',
|
||||
'change.payload as changePayload',
|
||||
'change.created_at as changeCreatedAt',
|
||||
'change.created_by as changeCreatedBy',
|
||||
'changeUser.username as changeCreatedByUsername',
|
||||
'changeUser.image_url as changeCreatedByAvatar',
|
||||
);
|
||||
};
|
||||
|
||||
getAll = async (): Promise<ISuggestChangeset[]> => {
|
||||
const rows = await this.buildSuggestChangeSetChangesQuery();
|
||||
return this.mapRows(rows);
|
||||
};
|
||||
|
||||
getForProject = async (project: string): Promise<ISuggestChangeset[]> => {
|
||||
const rows = await this.buildSuggestChangeSetChangesQuery().where({
|
||||
project,
|
||||
});
|
||||
return this.mapRows(rows);
|
||||
};
|
||||
|
||||
getDraftForUser = async (
|
||||
user: User,
|
||||
project: string,
|
||||
environment: string,
|
||||
): Promise<ISuggestChangeset> => {
|
||||
const rows = await this.buildSuggestChangeSetChangesQuery().where({
|
||||
'changeSet.created_by': user.id,
|
||||
state: 'Draft',
|
||||
project: project,
|
||||
environment: environment,
|
||||
});
|
||||
const change = this.mapRows(rows)[0];
|
||||
return change;
|
||||
};
|
||||
|
||||
getForEnvironment = async (
|
||||
environment: string,
|
||||
): Promise<ISuggestChangeset[]> => {
|
||||
const rows = await this.buildSuggestChangeSetChangesQuery().where({
|
||||
environment,
|
||||
});
|
||||
|
||||
return this.mapRows(rows);
|
||||
};
|
||||
|
||||
get = async (id: number): Promise<ISuggestChangeset> => {
|
||||
const rows = await this.buildSuggestChangeSetChangesQuery().where({
|
||||
'changeSet.id': id,
|
||||
});
|
||||
|
||||
return this.mapRows(rows)[0];
|
||||
};
|
||||
|
||||
create = async (
|
||||
suggestChangeSet: PartialSome<
|
||||
ISuggestChangeset,
|
||||
'id' | 'createdBy' | 'createdAt'
|
||||
>,
|
||||
user: User,
|
||||
): Promise<ISuggestChangeset> => {
|
||||
const [{ id }] = await this.db(T.SUGGEST_CHANGE_SET)
|
||||
.insert<ISuggestChangesetInsert>({
|
||||
environment: suggestChangeSet.environment,
|
||||
state: suggestChangeSet.state,
|
||||
project: suggestChangeSet.project,
|
||||
created_by: user.id,
|
||||
})
|
||||
.returning('id');
|
||||
|
||||
suggestChangeSet.changes.forEach((change) => {
|
||||
this.addChangeToSet(change, id, user);
|
||||
});
|
||||
|
||||
return this.get(id);
|
||||
};
|
||||
|
||||
addChangeToSet = async (
|
||||
change: PartialSome<ISuggestChange, 'id' | 'createdBy' | 'createdAt'>,
|
||||
changeSetID: number,
|
||||
user: User,
|
||||
): Promise<void> => {
|
||||
await this.db(T.SUGGEST_CHANGE)
|
||||
.insert<ISuggestChangeInsert>({
|
||||
action: change.action,
|
||||
feature: change.feature,
|
||||
payload: change.payload,
|
||||
suggest_change_set_id: changeSetID,
|
||||
created_by: user.id,
|
||||
})
|
||||
.returning('id');
|
||||
};
|
||||
|
||||
delete = (id: number): Promise<void> => {
|
||||
return this.db(T.SUGGEST_CHANGE_SET).where({ id }).del();
|
||||
};
|
||||
|
||||
deleteAll = (): Promise<void> => {
|
||||
return this.db(T.SUGGEST_CHANGE_SET).del();
|
||||
};
|
||||
|
||||
exists = async (id: number): Promise<boolean> => {
|
||||
const result = await this.db.raw(
|
||||
`SELECT EXISTS(SELECT 1 FROM ${T.SUGGEST_CHANGE_SET} WHERE id = ?) AS present`,
|
||||
[id],
|
||||
);
|
||||
|
||||
return result.rows[0].present;
|
||||
};
|
||||
|
||||
mapRows = (rows?: any[]): ISuggestChangeset[] => {
|
||||
const suggestChangeSets = rows.reduce(suggestChangeRowReducer, {});
|
||||
return Object.values(suggestChangeSets);
|
||||
};
|
||||
|
||||
destroy(): void {}
|
||||
}
|
@ -82,6 +82,8 @@ export const PUBLIC_SIGNUP_TOKEN_CREATED = 'public-signup-token-created';
|
||||
export const PUBLIC_SIGNUP_TOKEN_USER_ADDED = 'public-signup-token-user-added';
|
||||
export const PUBLIC_SIGNUP_TOKEN_TOKEN_UPDATED = 'public-signup-token-updated';
|
||||
|
||||
export const SUGGEST_CHANGE_CREATED = 'suggest-change-created';
|
||||
|
||||
export interface IBaseEvent {
|
||||
type: string;
|
||||
createdBy: string;
|
||||
|
@ -14,14 +14,14 @@ export const defaultExperimentalOptions = {
|
||||
process.env.UNLEASH_EXPERIMENTAL_PERSONAL_ACCESS_TOKENS,
|
||||
false,
|
||||
),
|
||||
syncSSOGroups: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_SYNC_SSO_GROUPS,
|
||||
false,
|
||||
),
|
||||
suggestChanges: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_SUGGEST_CHANGES,
|
||||
false,
|
||||
),
|
||||
syncSSOGroups: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_SYNC_SSO_GROUPS,
|
||||
false,
|
||||
),
|
||||
embedProxyFrontend: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_EMBED_PROXY_FRONTEND,
|
||||
false,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ITagType } from './stores/tag-type-store';
|
||||
import { LogProvider } from '../logger';
|
||||
import { IRole } from './stores/access-store';
|
||||
import { IUser } from './user';
|
||||
import User, { IUser } from './user';
|
||||
import { ALL_OPERATORS } from '../util/constants';
|
||||
|
||||
export type Operator = typeof ALL_OPERATORS[number];
|
||||
@ -365,3 +365,54 @@ export interface IFeatureStrategySegment {
|
||||
featureStrategyId: string;
|
||||
segmentId: number;
|
||||
}
|
||||
|
||||
export interface ISuggestChangeset {
|
||||
id: number;
|
||||
state: string;
|
||||
project: string;
|
||||
environment: string;
|
||||
createdBy: Pick<User, 'id' | 'username' | 'imageUrl'>;
|
||||
createdAt: Date;
|
||||
changes: ISuggestChange[];
|
||||
}
|
||||
|
||||
export interface ISuggestChangePayload {
|
||||
environment: string;
|
||||
data: unknown;
|
||||
}
|
||||
|
||||
export interface ISuggestChange {
|
||||
id?: number;
|
||||
action: SuggestChangeAction;
|
||||
feature: string;
|
||||
payload: ISuggestChangePayload;
|
||||
createdBy?: Pick<User, 'id' | 'username' | 'imageUrl'>;
|
||||
createdAt?: Date;
|
||||
}
|
||||
|
||||
export enum SuggestChangesetEvent {
|
||||
CREATED = 'CREATED',
|
||||
UPDATED = 'UPDATED',
|
||||
SUBMITTED = 'SUBMITTED',
|
||||
APPROVED = 'APPROVED',
|
||||
REJECTED = 'REJECTED',
|
||||
CLOSED = 'CLOSED',
|
||||
}
|
||||
|
||||
export enum SuggestChangeAction {
|
||||
UPDATE_ENABLED = 'updateEnabled',
|
||||
ADD_STRATEGY = 'strategyAdd',
|
||||
UPDATE_STRATEGY = 'strategyUpdate',
|
||||
DELETE_STRATEGY = 'strategyDelete',
|
||||
}
|
||||
|
||||
export enum SuggestChangeEvent {
|
||||
UPDATE_ENABLED = 'updateFeatureEnabledEvent',
|
||||
ADD_STRATEGY = 'addStrategyEvent',
|
||||
UPDATE_STRATEGY = 'updateStrategyEvent',
|
||||
DELETE_STRATEGY = 'deleteStrategyEvent',
|
||||
}
|
||||
export interface ISuggestChangeEventData {
|
||||
feature: string;
|
||||
data: unknown;
|
||||
}
|
||||
|
@ -37,3 +37,4 @@ export const MOVE_FEATURE_TOGGLE = 'MOVE_FEATURE_TOGGLE';
|
||||
export const CREATE_SEGMENT = 'CREATE_SEGMENT';
|
||||
export const UPDATE_SEGMENT = 'UPDATE_SEGMENT';
|
||||
export const DELETE_SEGMENT = 'DELETE_SEGMENT';
|
||||
export const SUGGEST_CHANGE = 'SUGGEST_CHANGE';
|
||||
|
@ -28,6 +28,7 @@ import { ISegmentStore } from './stores/segment-store';
|
||||
import { IGroupStore } from './stores/group-store';
|
||||
import { IPatStore } from './stores/pat-store';
|
||||
import { IPublicSignupTokenStore } from './stores/public-signup-token-store';
|
||||
import { ISuggestChangeStore } from './stores/suggest-change-store';
|
||||
|
||||
export interface IUnleashStores {
|
||||
accessStore: IAccessStore;
|
||||
@ -60,4 +61,5 @@ export interface IUnleashStores {
|
||||
segmentStore: ISegmentStore;
|
||||
patStore: IPatStore;
|
||||
publicSignupTokenStore: IPublicSignupTokenStore;
|
||||
suggestChangeStore: ISuggestChangeStore;
|
||||
}
|
||||
|
34
src/lib/types/stores/suggest-change-store.ts
Normal file
34
src/lib/types/stores/suggest-change-store.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { Store } from './store';
|
||||
import { ISuggestChange, ISuggestChangeset } from '../model';
|
||||
import { PartialSome } from '../partial';
|
||||
import User from '../user';
|
||||
|
||||
export interface ISuggestChangeStore extends Store<ISuggestChangeset, number> {
|
||||
create(
|
||||
suggestChangeSet: PartialSome<
|
||||
ISuggestChangeset,
|
||||
'id' | 'createdBy' | 'createdAt'
|
||||
>,
|
||||
user: Partial<Pick<User, 'username' | 'email'>>,
|
||||
): Promise<ISuggestChangeset>;
|
||||
|
||||
addChangeToSet(
|
||||
change: PartialSome<ISuggestChange, 'id' | 'createdBy' | 'createdAt'>,
|
||||
changeSetID: number,
|
||||
user: User,
|
||||
): Promise<void>;
|
||||
|
||||
get(id: number): Promise<ISuggestChangeset>;
|
||||
|
||||
getAll(): Promise<ISuggestChangeset[]>;
|
||||
|
||||
getForProject(project: string): Promise<ISuggestChangeset[]>;
|
||||
|
||||
getDraftForUser(
|
||||
user: User,
|
||||
project: string,
|
||||
environment: string,
|
||||
): Promise<ISuggestChangeset>;
|
||||
|
||||
getForEnvironment(environment: string): Promise<ISuggestChangeset[]>;
|
||||
}
|
37
src/migrations/20221810114644-add-suggest-changes-table.js
Normal file
37
src/migrations/20221810114644-add-suggest-changes-table.js
Normal file
@ -0,0 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
exports.up = function (db, callback) {
|
||||
db.runSql(
|
||||
`
|
||||
CREATE TABLE IF NOT EXISTS suggest_change_set (
|
||||
id serial primary key,
|
||||
environment varchar(100) REFERENCES environments(name) ON DELETE CASCADE,
|
||||
state varchar(255) NOT NULL,
|
||||
project varchar(255) REFERENCES projects(id) ON DELETE CASCADE,
|
||||
created_by integer not null references users (id) ON DELETE CASCADE,
|
||||
created_at timestamp default now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS suggest_change (
|
||||
id serial primary key,
|
||||
feature varchar(255) NOT NULL references features(name) on delete cascade,
|
||||
action varchar(255) NOT NULL,
|
||||
payload jsonb not null default '[]'::jsonb,
|
||||
created_by integer not null references users (id) ON DELETE CASCADE,
|
||||
created_at timestamp default now(),
|
||||
suggest_change_set_id integer NOT NULL REFERENCES suggest_change_set(id) ON DELETE CASCADE
|
||||
);
|
||||
`,
|
||||
callback,
|
||||
);
|
||||
};
|
||||
|
||||
exports.down = function (db, callback) {
|
||||
db.runSql(
|
||||
`
|
||||
DROP TABLE IF EXISTS suggest_change;
|
||||
DROP TABLE IF EXISTS suggest_change_set;
|
||||
`,
|
||||
callback,
|
||||
);
|
||||
};
|
@ -29,6 +29,7 @@ export function createTestConfig(config?: IUnleashOptions): IUnleashConfig {
|
||||
batchMetrics: true,
|
||||
personalAccessTokens: true,
|
||||
syncSSOGroups: true,
|
||||
suggestChanges: true,
|
||||
cloneEnvironment: true,
|
||||
},
|
||||
},
|
||||
|
90
src/test/fixtures/fake-suggest-change-store.ts
vendored
Normal file
90
src/test/fixtures/fake-suggest-change-store.ts
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
import { ISuggestChangeStore } from '../../lib/types/stores/suggest-change-store';
|
||||
import { ISuggestChange, ISuggestChangeset } from '../../lib/types/model';
|
||||
import { PartialSome } from '../../lib/types/partial';
|
||||
import User from '../../lib/types/user';
|
||||
|
||||
export default class FakeSuggestChangeStore implements ISuggestChangeStore {
|
||||
suggestChanges: ISuggestChangeset[] = [];
|
||||
|
||||
async get(id: number): Promise<ISuggestChangeset> {
|
||||
const change = this.suggestChanges.find((c) => c.id === id);
|
||||
return Promise.resolve(change);
|
||||
}
|
||||
|
||||
async count(): Promise<number> {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
|
||||
async delete(id: number): Promise<void> {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
addChangeToSet(
|
||||
change: PartialSome<ISuggestChange, 'id' | 'createdBy' | 'createdAt'>,
|
||||
changeSetID: number,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
user: User,
|
||||
): Promise<void> {
|
||||
const changeSet = this.suggestChanges.find((s) => s.id === changeSetID);
|
||||
changeSet.changes.push(change);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
getForEnvironment(environment: string): Promise<ISuggestChangeset[]> {
|
||||
return Promise.resolve(
|
||||
this.suggestChanges.filter(
|
||||
(changeSet) => changeSet.environment === environment,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
getDraftForUser(
|
||||
user: User,
|
||||
project: string,
|
||||
environment: string,
|
||||
): Promise<ISuggestChangeset> {
|
||||
return Promise.resolve(
|
||||
this.suggestChanges.find(
|
||||
(changeSet) =>
|
||||
changeSet.project === project &&
|
||||
changeSet.environment === environment &&
|
||||
changeSet.createdBy.id === user.id,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
getForProject(project: string): Promise<ISuggestChangeset[]> {
|
||||
return Promise.resolve(
|
||||
this.suggestChanges.filter(
|
||||
(changeSet) => changeSet.project === project,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
create(
|
||||
suggestChangeSet: PartialSome<ISuggestChangeset, 'id'>,
|
||||
user: Partial<Pick<User, 'id' | 'username' | 'email'>>,
|
||||
): Promise<ISuggestChangeset> {
|
||||
this.suggestChanges.push({
|
||||
id: 1,
|
||||
...suggestChangeSet,
|
||||
createdBy: { id: user.id, username: user.email, imageUrl: '' },
|
||||
});
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
getAll(): Promise<ISuggestChangeset[]> {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
deleteAll(): Promise<void> {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
destroy(): void {}
|
||||
|
||||
exists(key: number): Promise<boolean> {
|
||||
return Promise.resolve(Boolean(key));
|
||||
}
|
||||
}
|
2
src/test/fixtures/store.ts
vendored
2
src/test/fixtures/store.ts
vendored
@ -29,6 +29,7 @@ import FakeSegmentStore from './fake-segment-store';
|
||||
import FakeGroupStore from './fake-group-store';
|
||||
import FakePatStore from './fake-pat-store';
|
||||
import FakePublicSignupStore from './fake-public-signup-store';
|
||||
import FakeSuggestChangeStore from './fake-suggest-change-store';
|
||||
|
||||
const createStores: () => IUnleashStores = () => {
|
||||
const db = {
|
||||
@ -69,6 +70,7 @@ const createStores: () => IUnleashStores = () => {
|
||||
groupStore: new FakeGroupStore(),
|
||||
patStore: new FakePatStore(),
|
||||
publicSignupTokenStore: new FakePublicSignupStore(),
|
||||
suggestChangeStore: new FakeSuggestChangeStore(),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1557,3 +1557,24 @@ This event fires when you delete a segment.
|
||||
"environment": null
|
||||
}
|
||||
```
|
||||
|
||||
## Suggest changes events
|
||||
|
||||
### 'suggest-change-created'
|
||||
|
||||
This event fires when you create a a suggest-changes draft.
|
||||
|
||||
```json title="example event: suggest-change-created"
|
||||
{
|
||||
"id": 971,
|
||||
"type": "suggest-change-created",
|
||||
"createdBy": "user@company.com",
|
||||
"createdAt": "2022-06-03T10:30:08.128Z",
|
||||
"data": {},
|
||||
"preData": null,
|
||||
"tags": [],
|
||||
"featureName": null,
|
||||
"project": null,
|
||||
"environment": null
|
||||
}
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user