diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index d16435a94fcd..0ac074923c43 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -1526,6 +1526,15 @@ components: example: "550e8400-e29b-41d4-a716-446655440000" format: uuid type: string + suggestion_id: + description: The ID of the flag suggestion. + in: path + name: suggestion_id + required: true + schema: + example: "550e8400-e29b-41d4-a716-446655440020" + format: uuid + type: string requestBodies: {} responses: BadRequestResponse: @@ -16318,6 +16327,62 @@ components: required: - data type: object + CreateFlagSuggestionAttributes: + description: Attributes for creating a flag suggestion. + properties: + action: + $ref: "#/components/schemas/FlagSuggestionAction" + comment: + description: Optional comment explaining the change. + example: "Archive this deprecated flag" + type: string + environment_id: + description: The environment ID for environment-scoped changes. + example: "550e8400-e29b-41d4-a716-446655440001" + format: uuid + type: string + notification_rule_targets: + description: |- + Notification handles (without @ prefix) to receive approval or rejection notifications. + For example, an email address or Slack channel name. + example: + - "user@example.com" + items: + type: string + minItems: 1 + type: array + property: + $ref: "#/components/schemas/FlagSuggestionProperty" + suggestion: + description: The suggested new value (empty string for flag-level actions like archive, JSON-encoded for complex properties like allocations). + example: "ENABLED" + type: string + suggestion_metadata: + $ref: "#/components/schemas/SuggestionMetadata" + required: + - action + - property + - notification_rule_targets + type: object + CreateFlagSuggestionData: + description: Data for creating a flag suggestion. + properties: + attributes: + $ref: "#/components/schemas/CreateFlagSuggestionAttributes" + type: + $ref: "#/components/schemas/FlagSuggestionDataType" + required: + - type + - attributes + type: object + CreateFlagSuggestionRequest: + description: Request to create a flag suggestion. + properties: + data: + $ref: "#/components/schemas/CreateFlagSuggestionData" + required: + - data + type: object CreateIncidentNotificationRuleRequest: description: Create request for a notification rule. properties: @@ -27026,6 +27091,194 @@ components: $ref: "#/components/schemas/FindingData" type: array type: object + FlagSuggestion: + description: A flag change suggestion. + properties: + attributes: + $ref: "#/components/schemas/FlagSuggestionAttributes" + id: + description: Unique identifier for the suggestion. + example: "550e8400-e29b-41d4-a716-446655440020" + format: uuid + type: string + type: + $ref: "#/components/schemas/FlagSuggestionDataType" + required: + - id + - type + - attributes + type: object + FlagSuggestionAction: + description: The type of change action for a suggestion. + enum: + - created + - updated + - deleted + - archived + - unarchived + - started + - stopped + - paused + - unpaused + example: archived + type: string + x-enum-varnames: + - CREATED + - UPDATED + - DELETED + - ARCHIVED + - UNARCHIVED + - STARTED + - STOPPED + - PAUSED + - UNPAUSED + FlagSuggestionAttributes: + description: Attributes of a flag suggestion. + properties: + action: + $ref: "#/components/schemas/FlagSuggestionAction" + base_flag_history_id: + description: The flag history version this suggestion was based on. + example: "550e8400-e29b-41d4-a716-446655440030" + format: uuid + type: string + comment: + description: Optional comment from the requester. + example: "Please archive this deprecated flag" + nullable: true + type: string + created_at: + description: When the suggestion was created. + example: "2024-01-15T10:30:00Z" + format: date-time + type: string + created_by: + description: UUID of the user who created the suggestion. + example: "550e8400-e29b-41d4-a716-446655440099" + format: uuid + type: string + current_status: + $ref: "#/components/schemas/FlagSuggestionStatus" + current_value: + description: The current value before the suggested change (empty string for flag-level actions like archive). + example: "DISABLED" + type: string + deleted_at: + description: When the suggestion was soft-deleted. + format: date-time + nullable: true + type: string + deleted_by: + description: UUID of the user who deleted the suggestion. + nullable: true + type: string + environment_id: + description: The environment ID for environment-scoped suggestions. Null for flag-level changes. + example: "550e8400-e29b-41d4-a716-446655440001" + nullable: true + type: string + feature_flag_id: + description: The ID of the feature flag this suggestion applies to. + example: "550e8400-e29b-41d4-a716-446655440000" + format: uuid + type: string + message: + description: Human-readable message about the suggestion (populated on auto-created suggestions). + example: "This flag requires approval to archive. A suggestion has been created and is pending review." + type: string + property: + $ref: "#/components/schemas/FlagSuggestionProperty" + suggestion: + description: The suggested new value (JSON-encoded for complex properties, empty string for flag-level actions like archive). + example: "ENABLED" + type: string + suggestion_metadata: + $ref: "#/components/schemas/SuggestionMetadata" + updated_at: + description: When the suggestion was last updated. + format: date-time + nullable: true + type: string + updated_by: + description: UUID of the user who last updated the suggestion. + nullable: true + type: string + required: + - feature_flag_id + - current_status + - action + - property + - created_by + - created_at + type: object + FlagSuggestionDataType: + description: Flag suggestions resource type. + enum: + - "flag-suggestions" + example: "flag-suggestions" + type: string + x-enum-varnames: + - FLAG_SUGGESTIONS + FlagSuggestionEventDataType: + description: Flag suggestion events resource type. + enum: + - "flag-suggestion-events" + example: "flag-suggestion-events" + type: string + x-enum-varnames: + - FLAG_SUGGESTION_EVENTS + FlagSuggestionProperty: + description: The flag property being changed. + enum: + - FLAG + - FLAG_NAME + - FLAG_DESCRIPTION + - JSON_SCHEMA + - DISTRIBUTION_CHANNEL + - VARIANT + - VARIANT_NAME + - VARIANT_VALUE + - ALLOCATIONS + - ROLLOUT + - ENVIRONMENT_STATUS + - DEFAULT_VARIANT + - OVERRIDE_VARIANT + example: FLAG + type: string + x-enum-varnames: + - FLAG + - FLAG_NAME + - FLAG_DESCRIPTION + - JSON_SCHEMA + - DISTRIBUTION_CHANNEL + - VARIANT + - VARIANT_NAME + - VARIANT_VALUE + - ALLOCATIONS + - ROLLOUT + - ENVIRONMENT_STATUS + - DEFAULT_VARIANT + - OVERRIDE_VARIANT + FlagSuggestionResponse: + description: Response containing a flag suggestion. + properties: + data: + $ref: "#/components/schemas/FlagSuggestion" + required: + - data + type: object + FlagSuggestionStatus: + description: The status of a flag suggestion. + enum: + - pending + - rejected + - approved + example: pending + type: string + x-enum-varnames: + - PENDING + - REJECTED + - APPROVED FlakyTest: description: A flaky test object. properties: @@ -57825,6 +58078,32 @@ components: description: Target revision ID to revert to type: string type: object + ReviewFlagSuggestionAttributes: + description: Attributes for reviewing a flag suggestion. + properties: + comment: + description: Optional comment from the reviewer. + example: "Looks good, approved!" + type: string + type: object + ReviewFlagSuggestionData: + description: Data for reviewing a flag suggestion. + properties: + attributes: + $ref: "#/components/schemas/ReviewFlagSuggestionAttributes" + type: + $ref: "#/components/schemas/FlagSuggestionEventDataType" + required: + - type + type: object + ReviewFlagSuggestionRequest: + description: Request to approve or reject a flag suggestion. + properties: + data: + $ref: "#/components/schemas/ReviewFlagSuggestionData" + required: + - data + type: object Role: description: Role object returned by the API. properties: @@ -70548,6 +70827,14 @@ components: format: double type: number type: object + SuggestionMetadata: + description: Optional metadata for a suggestion. + properties: + variant_id: + description: Variant ID for variant delete suggestions. + example: "550e8400-e29b-41d4-a716-446655440005" + type: string + type: object SuiteCreateEdit: description: Data object for creating or editing a Synthetic test suite. properties: @@ -91949,6 +92236,194 @@ paths: operator: AND permissions: - feature_flag_config_write + /api/v2/feature-flags/suggestions/{suggestion_id}: + delete: + description: |- + Delete a pending flag change suggestion. Approved suggestions cannot be deleted. + operationId: DeleteFlagSuggestion + parameters: + - $ref: "#/components/parameters/suggestion_id" + responses: + "204": + description: No Content + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Bad Request + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Forbidden + "404": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Not Found + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: [] + summary: Delete a flag suggestion + tags: + - Feature Flags + x-permission: + operator: AND + permissions: + - feature_flag_config_write + - feature_flag_environment_config_read + get: + description: |- + Get a flag change suggestion by ID. + operationId: GetFlagSuggestion + parameters: + - $ref: "#/components/parameters/suggestion_id" + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/FlagSuggestionResponse" + description: OK + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Bad Request + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Forbidden + "404": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Not Found + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: [] + summary: Get a flag suggestion + tags: + - Feature Flags + x-permission: + operator: AND + permissions: + - feature_flag_config_write + - feature_flag_environment_config_read + /api/v2/feature-flags/suggestions/{suggestion_id}/approve: + post: + description: |- + Approve a pending flag change suggestion. The change is applied immediately + upon approval. A user cannot approve their own suggestion. + operationId: ApproveFlagSuggestion + parameters: + - $ref: "#/components/parameters/suggestion_id" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ReviewFlagSuggestionRequest" + required: true + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/FlagSuggestionResponse" + description: OK + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Bad Request + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Forbidden - Cannot approve your own suggestion + "404": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Not Found + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: [] + summary: Approve a flag suggestion + tags: + - Feature Flags + x-permission: + operator: AND + permissions: + - feature_flag_config_write + - feature_flag_environment_config_read + /api/v2/feature-flags/suggestions/{suggestion_id}/reject: + post: + description: |- + Reject a pending flag change suggestion. The suggested change is not applied. + operationId: RejectFlagSuggestion + parameters: + - $ref: "#/components/parameters/suggestion_id" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ReviewFlagSuggestionRequest" + required: true + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/FlagSuggestionResponse" + description: OK + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Bad Request + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Forbidden + "404": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Not Found + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: [] + summary: Reject a flag suggestion + tags: + - Feature Flags + x-permission: + operator: AND + permissions: + - feature_flag_config_write + - feature_flag_environment_config_read /api/v2/feature-flags/{feature_flag_id}: get: description: |- @@ -92360,6 +92835,65 @@ paths: permissions: - feature_flag_config_write - feature_flag_environment_config_read + /api/v2/feature-flags/{feature_flag_id}/suggestions: + post: + description: |- + Create a change suggestion for a feature flag. Suggestions require approval + before the change is applied. The request must include at least one + notification_rule_targets handle to receive approval or rejection notifications. + operationId: CreateFlagSuggestion + parameters: + - $ref: "#/components/parameters/feature_flag_id" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateFlagSuggestionRequest" + required: true + responses: + "201": + content: + application/json: + schema: + $ref: "#/components/schemas/FlagSuggestionResponse" + description: Created + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Bad Request + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Forbidden + "404": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Not Found + "409": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Conflict + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: [] + summary: Create a flag suggestion + tags: + - Feature Flags + x-permission: + operator: AND + permissions: + - feature_flag_config_write + - feature_flag_environment_config_read /api/v2/feature-flags/{feature_flag_id}/unarchive: post: description: |- diff --git a/features/v2/feature_flags.feature b/features/v2/feature_flags.feature index fd2ff16520c5..b2642c78ca51 100644 --- a/features/v2/feature_flags.feature +++ b/features/v2/feature_flags.feature @@ -7,6 +7,30 @@ Feature: Feature Flags And a valid "appKeyAuth" key in the system And an instance of "FeatureFlags" API + @generated @skip @team:DataDog/feature-flags + Scenario: Approve a flag suggestion returns "Bad Request" response + Given new "ApproveFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + And body with value {"data": {"attributes": {"comment": "Looks good, approved!"}, "type": "flag-suggestion-events"}} + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/feature-flags + Scenario: Approve a flag suggestion returns "Not Found" response + Given new "ApproveFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + And body with value {"data": {"attributes": {"comment": "Looks good, approved!"}, "type": "flag-suggestion-events"}} + When the request is sent + Then the response status is 404 Not Found + + @generated @skip @team:DataDog/feature-flags + Scenario: Approve a flag suggestion returns "OK" response + Given new "ApproveFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + And body with value {"data": {"attributes": {"comment": "Looks good, approved!"}, "type": "flag-suggestion-events"}} + When the request is sent + Then the response status is 200 OK + @skip @team:DataDog/feature-flags Scenario: Archive a feature flag returns "Bad Request" response Given new "ArchiveFeatureFlag" request @@ -53,6 +77,38 @@ Feature: Feature Flags And the response "data.attributes.name" is equal to "Test Feature Flag {{ unique }}" And the response "data.attributes.value_type" is equal to "BOOLEAN" + @generated @skip @team:DataDog/feature-flags + Scenario: Create a flag suggestion returns "Bad Request" response + Given new "CreateFlagSuggestion" request + And request contains "feature_flag_id" parameter from "REPLACE.ME" + And body with value {"data": {"attributes": {"action": "archived", "comment": "Archive this deprecated flag", "environment_id": "550e8400-e29b-41d4-a716-446655440001", "notification_rule_targets": ["user@example.com"], "property": "FLAG", "suggestion": "ENABLED", "suggestion_metadata": {"variant_id": "550e8400-e29b-41d4-a716-446655440005"}}, "type": "flag-suggestions"}} + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/feature-flags + Scenario: Create a flag suggestion returns "Conflict" response + Given new "CreateFlagSuggestion" request + And request contains "feature_flag_id" parameter from "REPLACE.ME" + And body with value {"data": {"attributes": {"action": "archived", "comment": "Archive this deprecated flag", "environment_id": "550e8400-e29b-41d4-a716-446655440001", "notification_rule_targets": ["user@example.com"], "property": "FLAG", "suggestion": "ENABLED", "suggestion_metadata": {"variant_id": "550e8400-e29b-41d4-a716-446655440005"}}, "type": "flag-suggestions"}} + When the request is sent + Then the response status is 409 Conflict + + @generated @skip @team:DataDog/feature-flags + Scenario: Create a flag suggestion returns "Created" response + Given new "CreateFlagSuggestion" request + And request contains "feature_flag_id" parameter from "REPLACE.ME" + And body with value {"data": {"attributes": {"action": "archived", "comment": "Archive this deprecated flag", "environment_id": "550e8400-e29b-41d4-a716-446655440001", "notification_rule_targets": ["user@example.com"], "property": "FLAG", "suggestion": "ENABLED", "suggestion_metadata": {"variant_id": "550e8400-e29b-41d4-a716-446655440005"}}, "type": "flag-suggestions"}} + When the request is sent + Then the response status is 201 Created + + @generated @skip @team:DataDog/feature-flags + Scenario: Create a flag suggestion returns "Not Found" response + Given new "CreateFlagSuggestion" request + And request contains "feature_flag_id" parameter from "REPLACE.ME" + And body with value {"data": {"attributes": {"action": "archived", "comment": "Archive this deprecated flag", "environment_id": "550e8400-e29b-41d4-a716-446655440001", "notification_rule_targets": ["user@example.com"], "property": "FLAG", "suggestion": "ENABLED", "suggestion_metadata": {"variant_id": "550e8400-e29b-41d4-a716-446655440005"}}, "type": "flag-suggestions"}} + When the request is sent + Then the response status is 404 Not Found + @team:DataDog/feature-flags Scenario: Create allocation for a flag in an environment returns "Created" response Given there is a valid "feature_flag" in the system @@ -130,6 +186,27 @@ Feature: Feature Flags When the request is sent Then the response status is 404 Not Found + @generated @skip @team:DataDog/feature-flags + Scenario: Delete a flag suggestion returns "Bad Request" response + Given new "DeleteFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/feature-flags + Scenario: Delete a flag suggestion returns "No Content" response + Given new "DeleteFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 204 No Content + + @generated @skip @team:DataDog/feature-flags + Scenario: Delete a flag suggestion returns "Not Found" response + Given new "DeleteFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 404 Not Found + @skip @team:DataDog/feature-flags Scenario: Delete an environment returns "No Content" response Given there is a valid "environment" in the system @@ -219,6 +296,27 @@ Feature: Feature Flags And the response "data.attributes.name" has the same value as "feature_flag.data.attributes.name" And the response "data.attributes.value_type" has the same value as "feature_flag.data.attributes.value_type" + @generated @skip @team:DataDog/feature-flags + Scenario: Get a flag suggestion returns "Bad Request" response + Given new "GetFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/feature-flags + Scenario: Get a flag suggestion returns "Not Found" response + Given new "GetFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 404 Not Found + + @generated @skip @team:DataDog/feature-flags + Scenario: Get a flag suggestion returns "OK" response + Given new "GetFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 200 OK + @skip @team:DataDog/feature-flags Scenario: Get an environment returns "Not Found" response Given new "GetFeatureFlagsEnvironment" request @@ -274,6 +372,30 @@ Feature: Feature Flags When the request is sent Then the response status is 200 OK + @generated @skip @team:DataDog/feature-flags + Scenario: Reject a flag suggestion returns "Bad Request" response + Given new "RejectFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + And body with value {"data": {"attributes": {"comment": "Looks good, approved!"}, "type": "flag-suggestion-events"}} + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/feature-flags + Scenario: Reject a flag suggestion returns "Not Found" response + Given new "RejectFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + And body with value {"data": {"attributes": {"comment": "Looks good, approved!"}, "type": "flag-suggestion-events"}} + When the request is sent + Then the response status is 404 Not Found + + @generated @skip @team:DataDog/feature-flags + Scenario: Reject a flag suggestion returns "OK" response + Given new "RejectFlagSuggestion" request + And request contains "suggestion_id" parameter from "REPLACE.ME" + And body with value {"data": {"attributes": {"comment": "Looks good, approved!"}, "type": "flag-suggestion-events"}} + When the request is sent + Then the response status is 200 OK + @generated @skip @team:DataDog/feature-flags Scenario: Resume a progressive rollout returns "Bad Request" response Given new "ResumeExposureSchedule" request diff --git a/features/v2/undo.json b/features/v2/undo.json index bbfa27e028c6..eae2df8f1b88 100644 --- a/features/v2/undo.json +++ b/features/v2/undo.json @@ -1954,6 +1954,30 @@ "type": "idempotent" } }, + "DeleteFlagSuggestion": { + "tag": "Feature Flags", + "undo": { + "type": "idempotent" + } + }, + "GetFlagSuggestion": { + "tag": "Feature Flags", + "undo": { + "type": "safe" + } + }, + "ApproveFlagSuggestion": { + "tag": "Feature Flags", + "undo": { + "type": "safe" + } + }, + "RejectFlagSuggestion": { + "tag": "Feature Flags", + "undo": { + "type": "safe" + } + }, "GetFeatureFlag": { "tag": "Feature Flags", "undo": { @@ -2003,6 +2027,19 @@ "type": "idempotent" } }, + "CreateFlagSuggestion": { + "tag": "Feature Flags", + "undo": { + "operationId": "DeleteFlagSuggestion", + "parameters": [ + { + "name": "suggestion_id", + "source": "data.id" + } + ], + "type": "unsafe" + } + }, "UnarchiveFeatureFlag": { "tag": "Feature Flags", "undo": { diff --git a/private/bdd_runner/src/support/scenarios_model_mapping.ts b/private/bdd_runner/src/support/scenarios_model_mapping.ts index 1c8c6ca992ba..c8780fe80b90 100644 --- a/private/bdd_runner/src/support/scenarios_model_mapping.ts +++ b/private/bdd_runner/src/support/scenarios_model_mapping.ts @@ -6623,6 +6623,42 @@ export const ScenariosModelMappings: { [key: string]: OperationMapping } = { }, operationResponseType: "AllocationExposureScheduleResponse", }, + "FeatureFlagsApi.V2.GetFlagSuggestion": { + suggestionId: { + type: "string", + format: "uuid", + }, + operationResponseType: "FlagSuggestionResponse", + }, + "FeatureFlagsApi.V2.DeleteFlagSuggestion": { + suggestionId: { + type: "string", + format: "uuid", + }, + operationResponseType: "{}", + }, + "FeatureFlagsApi.V2.ApproveFlagSuggestion": { + suggestionId: { + type: "string", + format: "uuid", + }, + body: { + type: "ReviewFlagSuggestionRequest", + format: "", + }, + operationResponseType: "FlagSuggestionResponse", + }, + "FeatureFlagsApi.V2.RejectFlagSuggestion": { + suggestionId: { + type: "string", + format: "uuid", + }, + body: { + type: "ReviewFlagSuggestionRequest", + format: "", + }, + operationResponseType: "FlagSuggestionResponse", + }, "FeatureFlagsApi.V2.GetFeatureFlag": { featureFlagId: { type: "string", @@ -6700,6 +6736,17 @@ export const ScenariosModelMappings: { [key: string]: OperationMapping } = { }, operationResponseType: "{}", }, + "FeatureFlagsApi.V2.CreateFlagSuggestion": { + featureFlagId: { + type: "string", + format: "uuid", + }, + body: { + type: "CreateFlagSuggestionRequest", + format: "", + }, + operationResponseType: "FlagSuggestionResponse", + }, "FeatureFlagsApi.V2.UnarchiveFeatureFlag": { featureFlagId: { type: "string", diff --git a/services/feature_flags/src/v2/FeatureFlagsApi.ts b/services/feature_flags/src/v2/FeatureFlagsApi.ts index 684935ee9b39..00ee07005b75 100644 --- a/services/feature_flags/src/v2/FeatureFlagsApi.ts +++ b/services/feature_flags/src/v2/FeatureFlagsApi.ts @@ -28,12 +28,15 @@ import { APIErrorResponse } from "./models/APIErrorResponse"; import { CreateAllocationsRequest } from "./models/CreateAllocationsRequest"; import { CreateEnvironmentRequest } from "./models/CreateEnvironmentRequest"; import { CreateFeatureFlagRequest } from "./models/CreateFeatureFlagRequest"; +import { CreateFlagSuggestionRequest } from "./models/CreateFlagSuggestionRequest"; import { EnvironmentResponse } from "./models/EnvironmentResponse"; import { FeatureFlagResponse } from "./models/FeatureFlagResponse"; +import { FlagSuggestionResponse } from "./models/FlagSuggestionResponse"; import { ListAllocationsResponse } from "./models/ListAllocationsResponse"; import { ListEnvironmentsResponse } from "./models/ListEnvironmentsResponse"; import { ListFeatureFlagsResponse } from "./models/ListFeatureFlagsResponse"; import { OverwriteAllocationsRequest } from "./models/OverwriteAllocationsRequest"; +import { ReviewFlagSuggestionRequest } from "./models/ReviewFlagSuggestionRequest"; import { UpdateEnvironmentRequest } from "./models/UpdateEnvironmentRequest"; import { UpdateFeatureFlagRequest } from "./models/UpdateFeatureFlagRequest"; import { version } from "../version"; @@ -47,6 +50,66 @@ export class FeatureFlagsApiRequestFactory extends BaseAPIRequestFactory { this.userAgent = buildUserAgent("feature-flags", version); } } + public async approveFlagSuggestion( + suggestionId: string, + body: ReviewFlagSuggestionRequest, + _options?: Configuration, + ): Promise { + const _config = _options || this.configuration; + + // verify required parameter 'suggestionId' is not null or undefined + if (suggestionId === null || suggestionId === undefined) { + throw new RequiredError("suggestionId", "approveFlagSuggestion"); + } + + // verify required parameter 'body' is not null or undefined + if (body === null || body === undefined) { + throw new RequiredError("body", "approveFlagSuggestion"); + } + + // Path Params + const localVarPath = + "/api/v2/feature-flags/suggestions/{suggestion_id}/approve".replace( + "{suggestion_id}", + encodeURIComponent(String(suggestionId)), + ); + + // Make Request Context + const { server, overrides } = _config.getServerAndOverrides( + "FeatureFlagsApi.v2.approveFlagSuggestion", + FeatureFlagsApi.operationServers, + ); + const requestContext = server.makeRequestContext( + localVarPath, + HttpMethod.POST, + overrides, + ); + requestContext.setHeaderParam("Accept", "application/json"); + requestContext.setHttpConfig(_config.httpConfig); + + // Set User-Agent + if (this.userAgent) { + requestContext.setHeaderParam("User-Agent", this.userAgent); + } + + // Body Params + const contentType = getPreferredMediaType(["application/json"]); + requestContext.setHeaderParam("Content-Type", contentType); + const serializedBody = stringify( + serialize(body, TypingInfo, "ReviewFlagSuggestionRequest", ""), + contentType, + ); + requestContext.setBody(serializedBody); + + // Apply auth methods + applySecurityAuthentication(_config, requestContext, [ + "apiKeyAuth", + "appKeyAuth", + ]); + + return requestContext; + } + public async archiveFeatureFlag( featureFlagId: string, _options?: Configuration, @@ -266,6 +329,66 @@ export class FeatureFlagsApiRequestFactory extends BaseAPIRequestFactory { return requestContext; } + public async createFlagSuggestion( + featureFlagId: string, + body: CreateFlagSuggestionRequest, + _options?: Configuration, + ): Promise { + const _config = _options || this.configuration; + + // verify required parameter 'featureFlagId' is not null or undefined + if (featureFlagId === null || featureFlagId === undefined) { + throw new RequiredError("featureFlagId", "createFlagSuggestion"); + } + + // verify required parameter 'body' is not null or undefined + if (body === null || body === undefined) { + throw new RequiredError("body", "createFlagSuggestion"); + } + + // Path Params + const localVarPath = + "/api/v2/feature-flags/{feature_flag_id}/suggestions".replace( + "{feature_flag_id}", + encodeURIComponent(String(featureFlagId)), + ); + + // Make Request Context + const { server, overrides } = _config.getServerAndOverrides( + "FeatureFlagsApi.v2.createFlagSuggestion", + FeatureFlagsApi.operationServers, + ); + const requestContext = server.makeRequestContext( + localVarPath, + HttpMethod.POST, + overrides, + ); + requestContext.setHeaderParam("Accept", "application/json"); + requestContext.setHttpConfig(_config.httpConfig); + + // Set User-Agent + if (this.userAgent) { + requestContext.setHeaderParam("User-Agent", this.userAgent); + } + + // Body Params + const contentType = getPreferredMediaType(["application/json"]); + requestContext.setHeaderParam("Content-Type", contentType); + const serializedBody = stringify( + serialize(body, TypingInfo, "CreateFlagSuggestionRequest", ""), + contentType, + ); + requestContext.setBody(serializedBody); + + // Apply auth methods + applySecurityAuthentication(_config, requestContext, [ + "apiKeyAuth", + "appKeyAuth", + ]); + + return requestContext; + } + public async deleteFeatureFlagsEnvironment( environmentId: string, _options?: Configuration, @@ -311,6 +434,51 @@ export class FeatureFlagsApiRequestFactory extends BaseAPIRequestFactory { return requestContext; } + public async deleteFlagSuggestion( + suggestionId: string, + _options?: Configuration, + ): Promise { + const _config = _options || this.configuration; + + // verify required parameter 'suggestionId' is not null or undefined + if (suggestionId === null || suggestionId === undefined) { + throw new RequiredError("suggestionId", "deleteFlagSuggestion"); + } + + // Path Params + const localVarPath = + "/api/v2/feature-flags/suggestions/{suggestion_id}".replace( + "{suggestion_id}", + encodeURIComponent(String(suggestionId)), + ); + + // Make Request Context + const { server, overrides } = _config.getServerAndOverrides( + "FeatureFlagsApi.v2.deleteFlagSuggestion", + FeatureFlagsApi.operationServers, + ); + const requestContext = server.makeRequestContext( + localVarPath, + HttpMethod.DELETE, + overrides, + ); + requestContext.setHeaderParam("Accept", "*/*"); + requestContext.setHttpConfig(_config.httpConfig); + + // Set User-Agent + if (this.userAgent) { + requestContext.setHeaderParam("User-Agent", this.userAgent); + } + + // Apply auth methods + applySecurityAuthentication(_config, requestContext, [ + "apiKeyAuth", + "appKeyAuth", + ]); + + return requestContext; + } + public async disableFeatureFlagEnvironment( featureFlagId: string, environmentId: string, @@ -500,6 +668,51 @@ export class FeatureFlagsApiRequestFactory extends BaseAPIRequestFactory { return requestContext; } + public async getFlagSuggestion( + suggestionId: string, + _options?: Configuration, + ): Promise { + const _config = _options || this.configuration; + + // verify required parameter 'suggestionId' is not null or undefined + if (suggestionId === null || suggestionId === undefined) { + throw new RequiredError("suggestionId", "getFlagSuggestion"); + } + + // Path Params + const localVarPath = + "/api/v2/feature-flags/suggestions/{suggestion_id}".replace( + "{suggestion_id}", + encodeURIComponent(String(suggestionId)), + ); + + // Make Request Context + const { server, overrides } = _config.getServerAndOverrides( + "FeatureFlagsApi.v2.getFlagSuggestion", + FeatureFlagsApi.operationServers, + ); + const requestContext = server.makeRequestContext( + localVarPath, + HttpMethod.GET, + overrides, + ); + requestContext.setHeaderParam("Accept", "application/json"); + requestContext.setHttpConfig(_config.httpConfig); + + // Set User-Agent + if (this.userAgent) { + requestContext.setHeaderParam("User-Agent", this.userAgent); + } + + // Apply auth methods + applySecurityAuthentication(_config, requestContext, [ + "apiKeyAuth", + "appKeyAuth", + ]); + + return requestContext; + } + public async listFeatureFlags( key?: string, isArchived?: boolean, @@ -683,6 +896,66 @@ export class FeatureFlagsApiRequestFactory extends BaseAPIRequestFactory { return requestContext; } + public async rejectFlagSuggestion( + suggestionId: string, + body: ReviewFlagSuggestionRequest, + _options?: Configuration, + ): Promise { + const _config = _options || this.configuration; + + // verify required parameter 'suggestionId' is not null or undefined + if (suggestionId === null || suggestionId === undefined) { + throw new RequiredError("suggestionId", "rejectFlagSuggestion"); + } + + // verify required parameter 'body' is not null or undefined + if (body === null || body === undefined) { + throw new RequiredError("body", "rejectFlagSuggestion"); + } + + // Path Params + const localVarPath = + "/api/v2/feature-flags/suggestions/{suggestion_id}/reject".replace( + "{suggestion_id}", + encodeURIComponent(String(suggestionId)), + ); + + // Make Request Context + const { server, overrides } = _config.getServerAndOverrides( + "FeatureFlagsApi.v2.rejectFlagSuggestion", + FeatureFlagsApi.operationServers, + ); + const requestContext = server.makeRequestContext( + localVarPath, + HttpMethod.POST, + overrides, + ); + requestContext.setHeaderParam("Accept", "application/json"); + requestContext.setHttpConfig(_config.httpConfig); + + // Set User-Agent + if (this.userAgent) { + requestContext.setHeaderParam("User-Agent", this.userAgent); + } + + // Body Params + const contentType = getPreferredMediaType(["application/json"]); + requestContext.setHeaderParam("Content-Type", contentType); + const serializedBody = stringify( + serialize(body, TypingInfo, "ReviewFlagSuggestionRequest", ""), + contentType, + ); + requestContext.setBody(serializedBody); + + // Apply auth methods + applySecurityAuthentication(_config, requestContext, [ + "apiKeyAuth", + "appKeyAuth", + ]); + + return requestContext; + } + public async resumeExposureSchedule( exposureScheduleId: string, _options?: Configuration, @@ -1058,6 +1331,67 @@ export class FeatureFlagsApiRequestFactory extends BaseAPIRequestFactory { } export class FeatureFlagsApiResponseProcessor { + /** + * Unwraps the actual response sent by the server from the response context and deserializes the response content + * to the expected objects + * + * @params response Response returned by the server for a request to approveFlagSuggestion + * @throws ApiException if the response code was not in [200, 299] + */ + public async approveFlagSuggestion( + response: ResponseContext, + ): Promise { + const contentType = normalizeMediaType(response.headers["content-type"]); + if (response.httpStatusCode === 200) { + const body: FlagSuggestionResponse = deserialize( + parse(await response.body.text(), contentType), + TypingInfo, + "FlagSuggestionResponse", + ) as FlagSuggestionResponse; + return body; + } + if ( + response.httpStatusCode === 400 || + response.httpStatusCode === 403 || + response.httpStatusCode === 404 || + response.httpStatusCode === 429 + ) { + const bodyText = parse(await response.body.text(), contentType); + let body: APIErrorResponse; + try { + body = deserialize( + bodyText, + TypingInfo, + "APIErrorResponse", + ) as APIErrorResponse; + } catch (error) { + logger.debug(`Got error deserializing error: ${error}`); + throw new ApiException( + response.httpStatusCode, + bodyText, + ); + } + throw new ApiException(response.httpStatusCode, body); + } + + // Work around for missing responses in specification, e.g. for petstore.yaml + if (response.httpStatusCode >= 200 && response.httpStatusCode <= 299) { + const body: FlagSuggestionResponse = deserialize( + parse(await response.body.text(), contentType), + TypingInfo, + "FlagSuggestionResponse", + "", + ) as FlagSuggestionResponse; + return body; + } + + const body = (await response.body.text()) || ""; + throw new ApiException( + response.httpStatusCode, + 'Unknown API Status Code!\nBody: "' + body + '"', + ); + } + /** * Unwraps the actual response sent by the server from the response context and deserializes the response content * to the expected objects @@ -1170,7 +1504,129 @@ export class FeatureFlagsApiResponseProcessor { TypingInfo, "AllocationResponse", "", - ) as AllocationResponse; + ) as AllocationResponse; + return body; + } + + const body = (await response.body.text()) || ""; + throw new ApiException( + response.httpStatusCode, + 'Unknown API Status Code!\nBody: "' + body + '"', + ); + } + + /** + * Unwraps the actual response sent by the server from the response context and deserializes the response content + * to the expected objects + * + * @params response Response returned by the server for a request to createFeatureFlag + * @throws ApiException if the response code was not in [200, 299] + */ + public async createFeatureFlag( + response: ResponseContext, + ): Promise { + const contentType = normalizeMediaType(response.headers["content-type"]); + if (response.httpStatusCode === 201) { + const body: FeatureFlagResponse = deserialize( + parse(await response.body.text(), contentType), + TypingInfo, + "FeatureFlagResponse", + ) as FeatureFlagResponse; + return body; + } + if ( + response.httpStatusCode === 400 || + response.httpStatusCode === 403 || + response.httpStatusCode === 409 || + response.httpStatusCode === 429 + ) { + const bodyText = parse(await response.body.text(), contentType); + let body: APIErrorResponse; + try { + body = deserialize( + bodyText, + TypingInfo, + "APIErrorResponse", + ) as APIErrorResponse; + } catch (error) { + logger.debug(`Got error deserializing error: ${error}`); + throw new ApiException( + response.httpStatusCode, + bodyText, + ); + } + throw new ApiException(response.httpStatusCode, body); + } + + // Work around for missing responses in specification, e.g. for petstore.yaml + if (response.httpStatusCode >= 200 && response.httpStatusCode <= 299) { + const body: FeatureFlagResponse = deserialize( + parse(await response.body.text(), contentType), + TypingInfo, + "FeatureFlagResponse", + "", + ) as FeatureFlagResponse; + return body; + } + + const body = (await response.body.text()) || ""; + throw new ApiException( + response.httpStatusCode, + 'Unknown API Status Code!\nBody: "' + body + '"', + ); + } + + /** + * Unwraps the actual response sent by the server from the response context and deserializes the response content + * to the expected objects + * + * @params response Response returned by the server for a request to createFeatureFlagsEnvironment + * @throws ApiException if the response code was not in [200, 299] + */ + public async createFeatureFlagsEnvironment( + response: ResponseContext, + ): Promise { + const contentType = normalizeMediaType(response.headers["content-type"]); + if (response.httpStatusCode === 201) { + const body: EnvironmentResponse = deserialize( + parse(await response.body.text(), contentType), + TypingInfo, + "EnvironmentResponse", + ) as EnvironmentResponse; + return body; + } + if ( + response.httpStatusCode === 400 || + response.httpStatusCode === 403 || + response.httpStatusCode === 409 || + response.httpStatusCode === 429 + ) { + const bodyText = parse(await response.body.text(), contentType); + let body: APIErrorResponse; + try { + body = deserialize( + bodyText, + TypingInfo, + "APIErrorResponse", + ) as APIErrorResponse; + } catch (error) { + logger.debug(`Got error deserializing error: ${error}`); + throw new ApiException( + response.httpStatusCode, + bodyText, + ); + } + throw new ApiException(response.httpStatusCode, body); + } + + // Work around for missing responses in specification, e.g. for petstore.yaml + if (response.httpStatusCode >= 200 && response.httpStatusCode <= 299) { + const body: EnvironmentResponse = deserialize( + parse(await response.body.text(), contentType), + TypingInfo, + "EnvironmentResponse", + "", + ) as EnvironmentResponse; return body; } @@ -1185,24 +1641,25 @@ export class FeatureFlagsApiResponseProcessor { * Unwraps the actual response sent by the server from the response context and deserializes the response content * to the expected objects * - * @params response Response returned by the server for a request to createFeatureFlag + * @params response Response returned by the server for a request to createFlagSuggestion * @throws ApiException if the response code was not in [200, 299] */ - public async createFeatureFlag( + public async createFlagSuggestion( response: ResponseContext, - ): Promise { + ): Promise { const contentType = normalizeMediaType(response.headers["content-type"]); if (response.httpStatusCode === 201) { - const body: FeatureFlagResponse = deserialize( + const body: FlagSuggestionResponse = deserialize( parse(await response.body.text(), contentType), TypingInfo, - "FeatureFlagResponse", - ) as FeatureFlagResponse; + "FlagSuggestionResponse", + ) as FlagSuggestionResponse; return body; } if ( response.httpStatusCode === 400 || response.httpStatusCode === 403 || + response.httpStatusCode === 404 || response.httpStatusCode === 409 || response.httpStatusCode === 429 ) { @@ -1226,12 +1683,12 @@ export class FeatureFlagsApiResponseProcessor { // Work around for missing responses in specification, e.g. for petstore.yaml if (response.httpStatusCode >= 200 && response.httpStatusCode <= 299) { - const body: FeatureFlagResponse = deserialize( + const body: FlagSuggestionResponse = deserialize( parse(await response.body.text(), contentType), TypingInfo, - "FeatureFlagResponse", + "FlagSuggestionResponse", "", - ) as FeatureFlagResponse; + ) as FlagSuggestionResponse; return body; } @@ -1246,25 +1703,19 @@ export class FeatureFlagsApiResponseProcessor { * Unwraps the actual response sent by the server from the response context and deserializes the response content * to the expected objects * - * @params response Response returned by the server for a request to createFeatureFlagsEnvironment + * @params response Response returned by the server for a request to deleteFeatureFlagsEnvironment * @throws ApiException if the response code was not in [200, 299] */ - public async createFeatureFlagsEnvironment( + public async deleteFeatureFlagsEnvironment( response: ResponseContext, - ): Promise { + ): Promise { const contentType = normalizeMediaType(response.headers["content-type"]); - if (response.httpStatusCode === 201) { - const body: EnvironmentResponse = deserialize( - parse(await response.body.text(), contentType), - TypingInfo, - "EnvironmentResponse", - ) as EnvironmentResponse; - return body; + if (response.httpStatusCode === 204) { + return; } if ( - response.httpStatusCode === 400 || response.httpStatusCode === 403 || - response.httpStatusCode === 409 || + response.httpStatusCode === 404 || response.httpStatusCode === 429 ) { const bodyText = parse(await response.body.text(), contentType); @@ -1287,13 +1738,7 @@ export class FeatureFlagsApiResponseProcessor { // Work around for missing responses in specification, e.g. for petstore.yaml if (response.httpStatusCode >= 200 && response.httpStatusCode <= 299) { - const body: EnvironmentResponse = deserialize( - parse(await response.body.text(), contentType), - TypingInfo, - "EnvironmentResponse", - "", - ) as EnvironmentResponse; - return body; + return; } const body = (await response.body.text()) || ""; @@ -1307,17 +1752,16 @@ export class FeatureFlagsApiResponseProcessor { * Unwraps the actual response sent by the server from the response context and deserializes the response content * to the expected objects * - * @params response Response returned by the server for a request to deleteFeatureFlagsEnvironment + * @params response Response returned by the server for a request to deleteFlagSuggestion * @throws ApiException if the response code was not in [200, 299] */ - public async deleteFeatureFlagsEnvironment( - response: ResponseContext, - ): Promise { + public async deleteFlagSuggestion(response: ResponseContext): Promise { const contentType = normalizeMediaType(response.headers["content-type"]); if (response.httpStatusCode === 204) { return; } if ( + response.httpStatusCode === 400 || response.httpStatusCode === 403 || response.httpStatusCode === 404 || response.httpStatusCode === 429 @@ -1570,6 +2014,67 @@ export class FeatureFlagsApiResponseProcessor { ); } + /** + * Unwraps the actual response sent by the server from the response context and deserializes the response content + * to the expected objects + * + * @params response Response returned by the server for a request to getFlagSuggestion + * @throws ApiException if the response code was not in [200, 299] + */ + public async getFlagSuggestion( + response: ResponseContext, + ): Promise { + const contentType = normalizeMediaType(response.headers["content-type"]); + if (response.httpStatusCode === 200) { + const body: FlagSuggestionResponse = deserialize( + parse(await response.body.text(), contentType), + TypingInfo, + "FlagSuggestionResponse", + ) as FlagSuggestionResponse; + return body; + } + if ( + response.httpStatusCode === 400 || + response.httpStatusCode === 403 || + response.httpStatusCode === 404 || + response.httpStatusCode === 429 + ) { + const bodyText = parse(await response.body.text(), contentType); + let body: APIErrorResponse; + try { + body = deserialize( + bodyText, + TypingInfo, + "APIErrorResponse", + ) as APIErrorResponse; + } catch (error) { + logger.debug(`Got error deserializing error: ${error}`); + throw new ApiException( + response.httpStatusCode, + bodyText, + ); + } + throw new ApiException(response.httpStatusCode, body); + } + + // Work around for missing responses in specification, e.g. for petstore.yaml + if (response.httpStatusCode >= 200 && response.httpStatusCode <= 299) { + const body: FlagSuggestionResponse = deserialize( + parse(await response.body.text(), contentType), + TypingInfo, + "FlagSuggestionResponse", + "", + ) as FlagSuggestionResponse; + return body; + } + + const body = (await response.body.text()) || ""; + throw new ApiException( + response.httpStatusCode, + 'Unknown API Status Code!\nBody: "' + body + '"', + ); + } + /** * Unwraps the actual response sent by the server from the response context and deserializes the response content * to the expected objects @@ -1744,6 +2249,67 @@ export class FeatureFlagsApiResponseProcessor { ); } + /** + * Unwraps the actual response sent by the server from the response context and deserializes the response content + * to the expected objects + * + * @params response Response returned by the server for a request to rejectFlagSuggestion + * @throws ApiException if the response code was not in [200, 299] + */ + public async rejectFlagSuggestion( + response: ResponseContext, + ): Promise { + const contentType = normalizeMediaType(response.headers["content-type"]); + if (response.httpStatusCode === 200) { + const body: FlagSuggestionResponse = deserialize( + parse(await response.body.text(), contentType), + TypingInfo, + "FlagSuggestionResponse", + ) as FlagSuggestionResponse; + return body; + } + if ( + response.httpStatusCode === 400 || + response.httpStatusCode === 403 || + response.httpStatusCode === 404 || + response.httpStatusCode === 429 + ) { + const bodyText = parse(await response.body.text(), contentType); + let body: APIErrorResponse; + try { + body = deserialize( + bodyText, + TypingInfo, + "APIErrorResponse", + ) as APIErrorResponse; + } catch (error) { + logger.debug(`Got error deserializing error: ${error}`); + throw new ApiException( + response.httpStatusCode, + bodyText, + ); + } + throw new ApiException(response.httpStatusCode, body); + } + + // Work around for missing responses in specification, e.g. for petstore.yaml + if (response.httpStatusCode >= 200 && response.httpStatusCode <= 299) { + const body: FlagSuggestionResponse = deserialize( + parse(await response.body.text(), contentType), + TypingInfo, + "FlagSuggestionResponse", + "", + ) as FlagSuggestionResponse; + return body; + } + + const body = (await response.body.text()) || ""; + throw new ApiException( + response.httpStatusCode, + 'Unknown API Status Code!\nBody: "' + body + '"', + ); + } + /** * Unwraps the actual response sent by the server from the response context and deserializes the response content * to the expected objects @@ -2176,6 +2742,18 @@ export class FeatureFlagsApiResponseProcessor { } } +export interface FeatureFlagsApiApproveFlagSuggestionRequest { + /** + * The ID of the flag suggestion. + * @type string + */ + suggestionId: string; + /** + * @type ReviewFlagSuggestionRequest + */ + body: ReviewFlagSuggestionRequest; +} + export interface FeatureFlagsApiArchiveFeatureFlagRequest { /** * The ID of the feature flag. @@ -2215,6 +2793,18 @@ export interface FeatureFlagsApiCreateFeatureFlagsEnvironmentRequest { body: CreateEnvironmentRequest; } +export interface FeatureFlagsApiCreateFlagSuggestionRequest { + /** + * The ID of the feature flag. + * @type string + */ + featureFlagId: string; + /** + * @type CreateFlagSuggestionRequest + */ + body: CreateFlagSuggestionRequest; +} + export interface FeatureFlagsApiDeleteFeatureFlagsEnvironmentRequest { /** * The ID of the environment. @@ -2223,6 +2813,14 @@ export interface FeatureFlagsApiDeleteFeatureFlagsEnvironmentRequest { environmentId: string; } +export interface FeatureFlagsApiDeleteFlagSuggestionRequest { + /** + * The ID of the flag suggestion. + * @type string + */ + suggestionId: string; +} + export interface FeatureFlagsApiDisableFeatureFlagEnvironmentRequest { /** * The ID of the feature flag. @@ -2265,6 +2863,14 @@ export interface FeatureFlagsApiGetFeatureFlagsEnvironmentRequest { environmentId: string; } +export interface FeatureFlagsApiGetFlagSuggestionRequest { + /** + * The ID of the flag suggestion. + * @type string + */ + suggestionId: string; +} + export interface FeatureFlagsApiListFeatureFlagsRequest { /** * Filter feature flags by key (partial matching). @@ -2319,6 +2925,18 @@ export interface FeatureFlagsApiPauseExposureScheduleRequest { exposureScheduleId: string; } +export interface FeatureFlagsApiRejectFlagSuggestionRequest { + /** + * The ID of the flag suggestion. + * @type string + */ + suggestionId: string; + /** + * @type ReviewFlagSuggestionRequest + */ + body: ReviewFlagSuggestionRequest; +} + export interface FeatureFlagsApiResumeExposureScheduleRequest { /** * The ID of the exposure schedule. @@ -2411,6 +3029,29 @@ export class FeatureFlagsApi { responseProcessor || new FeatureFlagsApiResponseProcessor(); } + /** + * Approve a pending flag change suggestion. The change is applied immediately + * upon approval. A user cannot approve their own suggestion. + * @param param The request object + */ + public approveFlagSuggestion( + param: FeatureFlagsApiApproveFlagSuggestionRequest, + options?: Configuration, + ): Promise { + const requestContextPromise = this.requestFactory.approveFlagSuggestion( + param.suggestionId, + param.body, + options, + ); + return requestContextPromise.then((requestContext) => { + return this.configuration.httpApi + .send(requestContext) + .then((responseContext) => { + return this.responseProcessor.approveFlagSuggestion(responseContext); + }); + }); + } + /** * Archives a feature flag. Archived flags are * hidden from the main list but remain accessible and can be unarchived. @@ -2501,6 +3142,30 @@ export class FeatureFlagsApi { }); } + /** + * Create a change suggestion for a feature flag. Suggestions require approval + * before the change is applied. The request must include at least one + * notification_rule_targets handle to receive approval or rejection notifications. + * @param param The request object + */ + public createFlagSuggestion( + param: FeatureFlagsApiCreateFlagSuggestionRequest, + options?: Configuration, + ): Promise { + const requestContextPromise = this.requestFactory.createFlagSuggestion( + param.featureFlagId, + param.body, + options, + ); + return requestContextPromise.then((requestContext) => { + return this.configuration.httpApi + .send(requestContext) + .then((responseContext) => { + return this.responseProcessor.createFlagSuggestion(responseContext); + }); + }); + } + /** * Deletes an environment. This operation cannot be undone. * @param param The request object @@ -2525,6 +3190,27 @@ export class FeatureFlagsApi { }); } + /** + * Delete a pending flag change suggestion. Approved suggestions cannot be deleted. + * @param param The request object + */ + public deleteFlagSuggestion( + param: FeatureFlagsApiDeleteFlagSuggestionRequest, + options?: Configuration, + ): Promise { + const requestContextPromise = this.requestFactory.deleteFlagSuggestion( + param.suggestionId, + options, + ); + return requestContextPromise.then((requestContext) => { + return this.configuration.httpApi + .send(requestContext) + .then((responseContext) => { + return this.responseProcessor.deleteFlagSuggestion(responseContext); + }); + }); + } + /** * Disable a feature flag in a specific environment. * @param param The request object @@ -2621,6 +3307,27 @@ export class FeatureFlagsApi { }); } + /** + * Get a flag change suggestion by ID. + * @param param The request object + */ + public getFlagSuggestion( + param: FeatureFlagsApiGetFlagSuggestionRequest, + options?: Configuration, + ): Promise { + const requestContextPromise = this.requestFactory.getFlagSuggestion( + param.suggestionId, + options, + ); + return requestContextPromise.then((requestContext) => { + return this.configuration.httpApi + .send(requestContext) + .then((responseContext) => { + return this.responseProcessor.getFlagSuggestion(responseContext); + }); + }); + } + /** * Returns a list of feature flags for the organization. * Supports filtering by key and archived status. @@ -2695,6 +3402,28 @@ export class FeatureFlagsApi { }); } + /** + * Reject a pending flag change suggestion. The suggested change is not applied. + * @param param The request object + */ + public rejectFlagSuggestion( + param: FeatureFlagsApiRejectFlagSuggestionRequest, + options?: Configuration, + ): Promise { + const requestContextPromise = this.requestFactory.rejectFlagSuggestion( + param.suggestionId, + param.body, + options, + ); + return requestContextPromise.then((requestContext) => { + return this.configuration.httpApi + .send(requestContext) + .then((responseContext) => { + return this.responseProcessor.rejectFlagSuggestion(responseContext); + }); + }); + } + /** * Resumes progression for a previously paused progressive rollout. * @param param The request object diff --git a/services/feature_flags/src/v2/index.ts b/services/feature_flags/src/v2/index.ts index 276405693bfb..b08eb75e71f9 100644 --- a/services/feature_flags/src/v2/index.ts +++ b/services/feature_flags/src/v2/index.ts @@ -1,16 +1,21 @@ export { + FeatureFlagsApiApproveFlagSuggestionRequest, FeatureFlagsApiArchiveFeatureFlagRequest, FeatureFlagsApiCreateAllocationsForFeatureFlagInEnvironmentRequest, FeatureFlagsApiCreateFeatureFlagRequest, FeatureFlagsApiCreateFeatureFlagsEnvironmentRequest, + FeatureFlagsApiCreateFlagSuggestionRequest, FeatureFlagsApiDeleteFeatureFlagsEnvironmentRequest, + FeatureFlagsApiDeleteFlagSuggestionRequest, FeatureFlagsApiDisableFeatureFlagEnvironmentRequest, FeatureFlagsApiEnableFeatureFlagEnvironmentRequest, FeatureFlagsApiGetFeatureFlagRequest, FeatureFlagsApiGetFeatureFlagsEnvironmentRequest, + FeatureFlagsApiGetFlagSuggestionRequest, FeatureFlagsApiListFeatureFlagsRequest, FeatureFlagsApiListFeatureFlagsEnvironmentsRequest, FeatureFlagsApiPauseExposureScheduleRequest, + FeatureFlagsApiRejectFlagSuggestionRequest, FeatureFlagsApiResumeExposureScheduleRequest, FeatureFlagsApiStartExposureScheduleRequest, FeatureFlagsApiStopExposureScheduleRequest, @@ -46,6 +51,9 @@ export { CreateFeatureFlagAttributes } from "./models/CreateFeatureFlagAttribute export { CreateFeatureFlagData } from "./models/CreateFeatureFlagData"; export { CreateFeatureFlagDataType } from "./models/CreateFeatureFlagDataType"; export { CreateFeatureFlagRequest } from "./models/CreateFeatureFlagRequest"; +export { CreateFlagSuggestionAttributes } from "./models/CreateFlagSuggestionAttributes"; +export { CreateFlagSuggestionData } from "./models/CreateFlagSuggestionData"; +export { CreateFlagSuggestionRequest } from "./models/CreateFlagSuggestionRequest"; export { CreateVariant } from "./models/CreateVariant"; export { Environment } from "./models/Environment"; export { EnvironmentAttributes } from "./models/EnvironmentAttributes"; @@ -61,6 +69,14 @@ export { FeatureFlagResponse } from "./models/FeatureFlagResponse"; export { FeatureFlagsPaginationMeta } from "./models/FeatureFlagsPaginationMeta"; export { FeatureFlagsPaginationMetaPage } from "./models/FeatureFlagsPaginationMetaPage"; export { FeatureFlagStatus } from "./models/FeatureFlagStatus"; +export { FlagSuggestion } from "./models/FlagSuggestion"; +export { FlagSuggestionAction } from "./models/FlagSuggestionAction"; +export { FlagSuggestionAttributes } from "./models/FlagSuggestionAttributes"; +export { FlagSuggestionDataType } from "./models/FlagSuggestionDataType"; +export { FlagSuggestionEventDataType } from "./models/FlagSuggestionEventDataType"; +export { FlagSuggestionProperty } from "./models/FlagSuggestionProperty"; +export { FlagSuggestionResponse } from "./models/FlagSuggestionResponse"; +export { FlagSuggestionStatus } from "./models/FlagSuggestionStatus"; export { GuardrailMetric } from "./models/GuardrailMetric"; export { GuardrailMetricRequest } from "./models/GuardrailMetricRequest"; export { GuardrailTriggerAction } from "./models/GuardrailTriggerAction"; @@ -68,9 +84,13 @@ export { ListAllocationsResponse } from "./models/ListAllocationsResponse"; export { ListEnvironmentsResponse } from "./models/ListEnvironmentsResponse"; export { ListFeatureFlagsResponse } from "./models/ListFeatureFlagsResponse"; export { OverwriteAllocationsRequest } from "./models/OverwriteAllocationsRequest"; +export { ReviewFlagSuggestionAttributes } from "./models/ReviewFlagSuggestionAttributes"; +export { ReviewFlagSuggestionData } from "./models/ReviewFlagSuggestionData"; +export { ReviewFlagSuggestionRequest } from "./models/ReviewFlagSuggestionRequest"; export { RolloutOptions } from "./models/RolloutOptions"; export { RolloutOptionsRequest } from "./models/RolloutOptionsRequest"; export { RolloutStrategy } from "./models/RolloutStrategy"; +export { SuggestionMetadata } from "./models/SuggestionMetadata"; export { TargetingRule } from "./models/TargetingRule"; export { TargetingRuleRequest } from "./models/TargetingRuleRequest"; export { UpdateEnvironmentAttributes } from "./models/UpdateEnvironmentAttributes"; diff --git a/services/feature_flags/src/v2/models/CreateFlagSuggestionAttributes.ts b/services/feature_flags/src/v2/models/CreateFlagSuggestionAttributes.ts new file mode 100644 index 000000000000..ac1fa08bdd0a --- /dev/null +++ b/services/feature_flags/src/v2/models/CreateFlagSuggestionAttributes.ts @@ -0,0 +1,101 @@ +import { AttributeTypeMap } from "@datadog/datadog-api-client"; + +import { FlagSuggestionAction } from "./FlagSuggestionAction"; +import { FlagSuggestionProperty } from "./FlagSuggestionProperty"; +import { SuggestionMetadata } from "./SuggestionMetadata"; + +/** + * Attributes for creating a flag suggestion. + */ +export class CreateFlagSuggestionAttributes { + /** + * The type of change action for a suggestion. + */ + "action": FlagSuggestionAction; + /** + * Optional comment explaining the change. + */ + "comment"?: string; + /** + * The environment ID for environment-scoped changes. + */ + "environmentId"?: string; + /** + * Notification handles (without @ prefix) to receive approval or rejection notifications. + * For example, an email address or Slack channel name. + */ + "notificationRuleTargets": Array; + /** + * The flag property being changed. + */ + "property": FlagSuggestionProperty; + /** + * The suggested new value (empty string for flag-level actions like archive, JSON-encoded for complex properties like allocations). + */ + "suggestion"?: string; + /** + * Optional metadata for a suggestion. + */ + "suggestionMetadata"?: SuggestionMetadata; + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + action: { + baseName: "action", + type: "FlagSuggestionAction", + required: true, + }, + comment: { + baseName: "comment", + type: "string", + }, + environmentId: { + baseName: "environment_id", + type: "string", + format: "uuid", + }, + notificationRuleTargets: { + baseName: "notification_rule_targets", + type: "Array", + required: true, + }, + property: { + baseName: "property", + type: "FlagSuggestionProperty", + required: true, + }, + suggestion: { + baseName: "suggestion", + type: "string", + }, + suggestionMetadata: { + baseName: "suggestion_metadata", + type: "SuggestionMetadata", + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return CreateFlagSuggestionAttributes.attributeTypeMap; + } + + public constructor() {} +} diff --git a/services/feature_flags/src/v2/models/CreateFlagSuggestionData.ts b/services/feature_flags/src/v2/models/CreateFlagSuggestionData.ts new file mode 100644 index 000000000000..691730c6ad24 --- /dev/null +++ b/services/feature_flags/src/v2/models/CreateFlagSuggestionData.ts @@ -0,0 +1,57 @@ +import { AttributeTypeMap } from "@datadog/datadog-api-client"; + +import { CreateFlagSuggestionAttributes } from "./CreateFlagSuggestionAttributes"; +import { FlagSuggestionDataType } from "./FlagSuggestionDataType"; + +/** + * Data for creating a flag suggestion. + */ +export class CreateFlagSuggestionData { + /** + * Attributes for creating a flag suggestion. + */ + "attributes": CreateFlagSuggestionAttributes; + /** + * Flag suggestions resource type. + */ + "type": FlagSuggestionDataType; + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + attributes: { + baseName: "attributes", + type: "CreateFlagSuggestionAttributes", + required: true, + }, + type: { + baseName: "type", + type: "FlagSuggestionDataType", + required: true, + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return CreateFlagSuggestionData.attributeTypeMap; + } + + public constructor() {} +} diff --git a/services/feature_flags/src/v2/models/CreateFlagSuggestionRequest.ts b/services/feature_flags/src/v2/models/CreateFlagSuggestionRequest.ts new file mode 100644 index 000000000000..76399d14f014 --- /dev/null +++ b/services/feature_flags/src/v2/models/CreateFlagSuggestionRequest.ts @@ -0,0 +1,47 @@ +import { AttributeTypeMap } from "@datadog/datadog-api-client"; + +import { CreateFlagSuggestionData } from "./CreateFlagSuggestionData"; + +/** + * Request to create a flag suggestion. + */ +export class CreateFlagSuggestionRequest { + /** + * Data for creating a flag suggestion. + */ + "data": CreateFlagSuggestionData; + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + data: { + baseName: "data", + type: "CreateFlagSuggestionData", + required: true, + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return CreateFlagSuggestionRequest.attributeTypeMap; + } + + public constructor() {} +} diff --git a/services/feature_flags/src/v2/models/FlagSuggestion.ts b/services/feature_flags/src/v2/models/FlagSuggestion.ts new file mode 100644 index 000000000000..cd623c3c8600 --- /dev/null +++ b/services/feature_flags/src/v2/models/FlagSuggestion.ts @@ -0,0 +1,67 @@ +import { AttributeTypeMap } from "@datadog/datadog-api-client"; + +import { FlagSuggestionAttributes } from "./FlagSuggestionAttributes"; +import { FlagSuggestionDataType } from "./FlagSuggestionDataType"; + +/** + * A flag change suggestion. + */ +export class FlagSuggestion { + /** + * Attributes of a flag suggestion. + */ + "attributes": FlagSuggestionAttributes; + /** + * Unique identifier for the suggestion. + */ + "id": string; + /** + * Flag suggestions resource type. + */ + "type": FlagSuggestionDataType; + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + attributes: { + baseName: "attributes", + type: "FlagSuggestionAttributes", + required: true, + }, + id: { + baseName: "id", + type: "string", + required: true, + format: "uuid", + }, + type: { + baseName: "type", + type: "FlagSuggestionDataType", + required: true, + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return FlagSuggestion.attributeTypeMap; + } + + public constructor() {} +} diff --git a/services/feature_flags/src/v2/models/FlagSuggestionAction.ts b/services/feature_flags/src/v2/models/FlagSuggestionAction.ts new file mode 100644 index 000000000000..be669c53d0f3 --- /dev/null +++ b/services/feature_flags/src/v2/models/FlagSuggestionAction.ts @@ -0,0 +1,25 @@ +import { UnparsedObject } from "@datadog/datadog-api-client"; + +/** + * The type of change action for a suggestion. + */ +export type FlagSuggestionAction = + | typeof CREATED + | typeof UPDATED + | typeof DELETED + | typeof ARCHIVED + | typeof UNARCHIVED + | typeof STARTED + | typeof STOPPED + | typeof PAUSED + | typeof UNPAUSED + | UnparsedObject; +export const CREATED = "created"; +export const UPDATED = "updated"; +export const DELETED = "deleted"; +export const ARCHIVED = "archived"; +export const UNARCHIVED = "unarchived"; +export const STARTED = "started"; +export const STOPPED = "stopped"; +export const PAUSED = "paused"; +export const UNPAUSED = "unpaused"; diff --git a/services/feature_flags/src/v2/models/FlagSuggestionAttributes.ts b/services/feature_flags/src/v2/models/FlagSuggestionAttributes.ts new file mode 100644 index 000000000000..16f2ca7e65d1 --- /dev/null +++ b/services/feature_flags/src/v2/models/FlagSuggestionAttributes.ts @@ -0,0 +1,189 @@ +import { AttributeTypeMap } from "@datadog/datadog-api-client"; + +import { FlagSuggestionAction } from "./FlagSuggestionAction"; +import { FlagSuggestionProperty } from "./FlagSuggestionProperty"; +import { FlagSuggestionStatus } from "./FlagSuggestionStatus"; +import { SuggestionMetadata } from "./SuggestionMetadata"; + +/** + * Attributes of a flag suggestion. + */ +export class FlagSuggestionAttributes { + /** + * The type of change action for a suggestion. + */ + "action": FlagSuggestionAction; + /** + * The flag history version this suggestion was based on. + */ + "baseFlagHistoryId"?: string; + /** + * Optional comment from the requester. + */ + "comment"?: string; + /** + * When the suggestion was created. + */ + "createdAt": Date; + /** + * UUID of the user who created the suggestion. + */ + "createdBy": string; + /** + * The status of a flag suggestion. + */ + "currentStatus": FlagSuggestionStatus; + /** + * The current value before the suggested change (empty string for flag-level actions like archive). + */ + "currentValue"?: string; + /** + * When the suggestion was soft-deleted. + */ + "deletedAt"?: Date; + /** + * UUID of the user who deleted the suggestion. + */ + "deletedBy"?: string; + /** + * The environment ID for environment-scoped suggestions. Null for flag-level changes. + */ + "environmentId"?: string; + /** + * The ID of the feature flag this suggestion applies to. + */ + "featureFlagId": string; + /** + * Human-readable message about the suggestion (populated on auto-created suggestions). + */ + "message"?: string; + /** + * The flag property being changed. + */ + "property": FlagSuggestionProperty; + /** + * The suggested new value (JSON-encoded for complex properties, empty string for flag-level actions like archive). + */ + "suggestion"?: string; + /** + * Optional metadata for a suggestion. + */ + "suggestionMetadata"?: SuggestionMetadata; + /** + * When the suggestion was last updated. + */ + "updatedAt"?: Date; + /** + * UUID of the user who last updated the suggestion. + */ + "updatedBy"?: string; + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + action: { + baseName: "action", + type: "FlagSuggestionAction", + required: true, + }, + baseFlagHistoryId: { + baseName: "base_flag_history_id", + type: "string", + format: "uuid", + }, + comment: { + baseName: "comment", + type: "string", + }, + createdAt: { + baseName: "created_at", + type: "Date", + required: true, + format: "date-time", + }, + createdBy: { + baseName: "created_by", + type: "string", + required: true, + format: "uuid", + }, + currentStatus: { + baseName: "current_status", + type: "FlagSuggestionStatus", + required: true, + }, + currentValue: { + baseName: "current_value", + type: "string", + }, + deletedAt: { + baseName: "deleted_at", + type: "Date", + format: "date-time", + }, + deletedBy: { + baseName: "deleted_by", + type: "string", + }, + environmentId: { + baseName: "environment_id", + type: "string", + }, + featureFlagId: { + baseName: "feature_flag_id", + type: "string", + required: true, + format: "uuid", + }, + message: { + baseName: "message", + type: "string", + }, + property: { + baseName: "property", + type: "FlagSuggestionProperty", + required: true, + }, + suggestion: { + baseName: "suggestion", + type: "string", + }, + suggestionMetadata: { + baseName: "suggestion_metadata", + type: "SuggestionMetadata", + }, + updatedAt: { + baseName: "updated_at", + type: "Date", + format: "date-time", + }, + updatedBy: { + baseName: "updated_by", + type: "string", + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return FlagSuggestionAttributes.attributeTypeMap; + } + + public constructor() {} +} diff --git a/services/feature_flags/src/v2/models/FlagSuggestionDataType.ts b/services/feature_flags/src/v2/models/FlagSuggestionDataType.ts new file mode 100644 index 000000000000..9f6aa079005b --- /dev/null +++ b/services/feature_flags/src/v2/models/FlagSuggestionDataType.ts @@ -0,0 +1,7 @@ +import { UnparsedObject } from "@datadog/datadog-api-client"; + +/** + * Flag suggestions resource type. + */ +export type FlagSuggestionDataType = typeof FLAG_SUGGESTIONS | UnparsedObject; +export const FLAG_SUGGESTIONS = "flag-suggestions"; diff --git a/services/feature_flags/src/v2/models/FlagSuggestionEventDataType.ts b/services/feature_flags/src/v2/models/FlagSuggestionEventDataType.ts new file mode 100644 index 000000000000..820c2d60e348 --- /dev/null +++ b/services/feature_flags/src/v2/models/FlagSuggestionEventDataType.ts @@ -0,0 +1,9 @@ +import { UnparsedObject } from "@datadog/datadog-api-client"; + +/** + * Flag suggestion events resource type. + */ +export type FlagSuggestionEventDataType = + | typeof FLAG_SUGGESTION_EVENTS + | UnparsedObject; +export const FLAG_SUGGESTION_EVENTS = "flag-suggestion-events"; diff --git a/services/feature_flags/src/v2/models/FlagSuggestionProperty.ts b/services/feature_flags/src/v2/models/FlagSuggestionProperty.ts new file mode 100644 index 000000000000..e4a38909bd07 --- /dev/null +++ b/services/feature_flags/src/v2/models/FlagSuggestionProperty.ts @@ -0,0 +1,33 @@ +import { UnparsedObject } from "@datadog/datadog-api-client"; + +/** + * The flag property being changed. + */ +export type FlagSuggestionProperty = + | typeof FLAG + | typeof FLAG_NAME + | typeof FLAG_DESCRIPTION + | typeof JSON_SCHEMA + | typeof DISTRIBUTION_CHANNEL + | typeof VARIANT + | typeof VARIANT_NAME + | typeof VARIANT_VALUE + | typeof ALLOCATIONS + | typeof ROLLOUT + | typeof ENVIRONMENT_STATUS + | typeof DEFAULT_VARIANT + | typeof OVERRIDE_VARIANT + | UnparsedObject; +export const FLAG = "FLAG"; +export const FLAG_NAME = "FLAG_NAME"; +export const FLAG_DESCRIPTION = "FLAG_DESCRIPTION"; +export const JSON_SCHEMA = "JSON_SCHEMA"; +export const DISTRIBUTION_CHANNEL = "DISTRIBUTION_CHANNEL"; +export const VARIANT = "VARIANT"; +export const VARIANT_NAME = "VARIANT_NAME"; +export const VARIANT_VALUE = "VARIANT_VALUE"; +export const ALLOCATIONS = "ALLOCATIONS"; +export const ROLLOUT = "ROLLOUT"; +export const ENVIRONMENT_STATUS = "ENVIRONMENT_STATUS"; +export const DEFAULT_VARIANT = "DEFAULT_VARIANT"; +export const OVERRIDE_VARIANT = "OVERRIDE_VARIANT"; diff --git a/services/feature_flags/src/v2/models/FlagSuggestionResponse.ts b/services/feature_flags/src/v2/models/FlagSuggestionResponse.ts new file mode 100644 index 000000000000..111bbe81701a --- /dev/null +++ b/services/feature_flags/src/v2/models/FlagSuggestionResponse.ts @@ -0,0 +1,47 @@ +import { AttributeTypeMap } from "@datadog/datadog-api-client"; + +import { FlagSuggestion } from "./FlagSuggestion"; + +/** + * Response containing a flag suggestion. + */ +export class FlagSuggestionResponse { + /** + * A flag change suggestion. + */ + "data": FlagSuggestion; + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + data: { + baseName: "data", + type: "FlagSuggestion", + required: true, + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return FlagSuggestionResponse.attributeTypeMap; + } + + public constructor() {} +} diff --git a/services/feature_flags/src/v2/models/FlagSuggestionStatus.ts b/services/feature_flags/src/v2/models/FlagSuggestionStatus.ts new file mode 100644 index 000000000000..17578fc2c9ff --- /dev/null +++ b/services/feature_flags/src/v2/models/FlagSuggestionStatus.ts @@ -0,0 +1,13 @@ +import { UnparsedObject } from "@datadog/datadog-api-client"; + +/** + * The status of a flag suggestion. + */ +export type FlagSuggestionStatus = + | typeof PENDING + | typeof REJECTED + | typeof APPROVED + | UnparsedObject; +export const PENDING = "pending"; +export const REJECTED = "rejected"; +export const APPROVED = "approved"; diff --git a/services/feature_flags/src/v2/models/ReviewFlagSuggestionAttributes.ts b/services/feature_flags/src/v2/models/ReviewFlagSuggestionAttributes.ts new file mode 100644 index 000000000000..b4f2ab632723 --- /dev/null +++ b/services/feature_flags/src/v2/models/ReviewFlagSuggestionAttributes.ts @@ -0,0 +1,44 @@ +import { AttributeTypeMap } from "@datadog/datadog-api-client"; + +/** + * Attributes for reviewing a flag suggestion. + */ +export class ReviewFlagSuggestionAttributes { + /** + * Optional comment from the reviewer. + */ + "comment"?: string; + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + comment: { + baseName: "comment", + type: "string", + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return ReviewFlagSuggestionAttributes.attributeTypeMap; + } + + public constructor() {} +} diff --git a/services/feature_flags/src/v2/models/ReviewFlagSuggestionData.ts b/services/feature_flags/src/v2/models/ReviewFlagSuggestionData.ts new file mode 100644 index 000000000000..295ceb1bb15a --- /dev/null +++ b/services/feature_flags/src/v2/models/ReviewFlagSuggestionData.ts @@ -0,0 +1,56 @@ +import { AttributeTypeMap } from "@datadog/datadog-api-client"; + +import { FlagSuggestionEventDataType } from "./FlagSuggestionEventDataType"; +import { ReviewFlagSuggestionAttributes } from "./ReviewFlagSuggestionAttributes"; + +/** + * Data for reviewing a flag suggestion. + */ +export class ReviewFlagSuggestionData { + /** + * Attributes for reviewing a flag suggestion. + */ + "attributes"?: ReviewFlagSuggestionAttributes; + /** + * Flag suggestion events resource type. + */ + "type": FlagSuggestionEventDataType; + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + attributes: { + baseName: "attributes", + type: "ReviewFlagSuggestionAttributes", + }, + type: { + baseName: "type", + type: "FlagSuggestionEventDataType", + required: true, + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return ReviewFlagSuggestionData.attributeTypeMap; + } + + public constructor() {} +} diff --git a/services/feature_flags/src/v2/models/ReviewFlagSuggestionRequest.ts b/services/feature_flags/src/v2/models/ReviewFlagSuggestionRequest.ts new file mode 100644 index 000000000000..e81be8840755 --- /dev/null +++ b/services/feature_flags/src/v2/models/ReviewFlagSuggestionRequest.ts @@ -0,0 +1,47 @@ +import { AttributeTypeMap } from "@datadog/datadog-api-client"; + +import { ReviewFlagSuggestionData } from "./ReviewFlagSuggestionData"; + +/** + * Request to approve or reject a flag suggestion. + */ +export class ReviewFlagSuggestionRequest { + /** + * Data for reviewing a flag suggestion. + */ + "data": ReviewFlagSuggestionData; + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + data: { + baseName: "data", + type: "ReviewFlagSuggestionData", + required: true, + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return ReviewFlagSuggestionRequest.attributeTypeMap; + } + + public constructor() {} +} diff --git a/services/feature_flags/src/v2/models/SuggestionMetadata.ts b/services/feature_flags/src/v2/models/SuggestionMetadata.ts new file mode 100644 index 000000000000..e6b244aca534 --- /dev/null +++ b/services/feature_flags/src/v2/models/SuggestionMetadata.ts @@ -0,0 +1,44 @@ +import { AttributeTypeMap } from "@datadog/datadog-api-client"; + +/** + * Optional metadata for a suggestion. + */ +export class SuggestionMetadata { + /** + * Variant ID for variant delete suggestions. + */ + "variantId"?: string; + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + variantId: { + baseName: "variant_id", + type: "string", + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return SuggestionMetadata.attributeTypeMap; + } + + public constructor() {} +} diff --git a/services/feature_flags/src/v2/models/TypingInfo.ts b/services/feature_flags/src/v2/models/TypingInfo.ts index ebdc151a5c6c..fe8fc9658fbd 100644 --- a/services/feature_flags/src/v2/models/TypingInfo.ts +++ b/services/feature_flags/src/v2/models/TypingInfo.ts @@ -19,6 +19,9 @@ import { CreateEnvironmentRequest } from "./CreateEnvironmentRequest"; import { CreateFeatureFlagAttributes } from "./CreateFeatureFlagAttributes"; import { CreateFeatureFlagData } from "./CreateFeatureFlagData"; import { CreateFeatureFlagRequest } from "./CreateFeatureFlagRequest"; +import { CreateFlagSuggestionAttributes } from "./CreateFlagSuggestionAttributes"; +import { CreateFlagSuggestionData } from "./CreateFlagSuggestionData"; +import { CreateFlagSuggestionRequest } from "./CreateFlagSuggestionRequest"; import { CreateVariant } from "./CreateVariant"; import { Environment } from "./Environment"; import { EnvironmentAttributes } from "./EnvironmentAttributes"; @@ -33,14 +36,21 @@ import { FeatureFlagEnvironment } from "./FeatureFlagEnvironment"; import { FeatureFlagResponse } from "./FeatureFlagResponse"; import { FeatureFlagsPaginationMeta } from "./FeatureFlagsPaginationMeta"; import { FeatureFlagsPaginationMetaPage } from "./FeatureFlagsPaginationMetaPage"; +import { FlagSuggestion } from "./FlagSuggestion"; +import { FlagSuggestionAttributes } from "./FlagSuggestionAttributes"; +import { FlagSuggestionResponse } from "./FlagSuggestionResponse"; import { GuardrailMetric } from "./GuardrailMetric"; import { GuardrailMetricRequest } from "./GuardrailMetricRequest"; import { ListAllocationsResponse } from "./ListAllocationsResponse"; import { ListEnvironmentsResponse } from "./ListEnvironmentsResponse"; import { ListFeatureFlagsResponse } from "./ListFeatureFlagsResponse"; import { OverwriteAllocationsRequest } from "./OverwriteAllocationsRequest"; +import { ReviewFlagSuggestionAttributes } from "./ReviewFlagSuggestionAttributes"; +import { ReviewFlagSuggestionData } from "./ReviewFlagSuggestionData"; +import { ReviewFlagSuggestionRequest } from "./ReviewFlagSuggestionRequest"; import { RolloutOptions } from "./RolloutOptions"; import { RolloutOptionsRequest } from "./RolloutOptionsRequest"; +import { SuggestionMetadata } from "./SuggestionMetadata"; import { TargetingRule } from "./TargetingRule"; import { TargetingRuleRequest } from "./TargetingRuleRequest"; import { UpdateEnvironmentAttributes } from "./UpdateEnvironmentAttributes"; @@ -74,6 +84,35 @@ export const TypingInfo: ModelTypingInfo = { CreateEnvironmentDataType: ["environments"], CreateFeatureFlagDataType: ["feature-flags"], FeatureFlagStatus: ["ENABLED", "DISABLED"], + FlagSuggestionAction: [ + "created", + "updated", + "deleted", + "archived", + "unarchived", + "started", + "stopped", + "paused", + "unpaused", + ], + FlagSuggestionDataType: ["flag-suggestions"], + FlagSuggestionEventDataType: ["flag-suggestion-events"], + FlagSuggestionProperty: [ + "FLAG", + "FLAG_NAME", + "FLAG_DESCRIPTION", + "JSON_SCHEMA", + "DISTRIBUTION_CHANNEL", + "VARIANT", + "VARIANT_NAME", + "VARIANT_VALUE", + "ALLOCATIONS", + "ROLLOUT", + "ENVIRONMENT_STATUS", + "DEFAULT_VARIANT", + "OVERRIDE_VARIANT", + ], + FlagSuggestionStatus: ["pending", "rejected", "approved"], GuardrailTriggerAction: ["PAUSE", "ABORT"], RolloutStrategy: ["UNIFORM_INTERVALS", "NO_ROLLOUT"], UpdateEnvironmentDataType: ["environments"], @@ -101,6 +140,9 @@ export const TypingInfo: ModelTypingInfo = { CreateFeatureFlagAttributes: CreateFeatureFlagAttributes, CreateFeatureFlagData: CreateFeatureFlagData, CreateFeatureFlagRequest: CreateFeatureFlagRequest, + CreateFlagSuggestionAttributes: CreateFlagSuggestionAttributes, + CreateFlagSuggestionData: CreateFlagSuggestionData, + CreateFlagSuggestionRequest: CreateFlagSuggestionRequest, CreateVariant: CreateVariant, Environment: Environment, EnvironmentAttributes: EnvironmentAttributes, @@ -115,14 +157,21 @@ export const TypingInfo: ModelTypingInfo = { FeatureFlagResponse: FeatureFlagResponse, FeatureFlagsPaginationMeta: FeatureFlagsPaginationMeta, FeatureFlagsPaginationMetaPage: FeatureFlagsPaginationMetaPage, + FlagSuggestion: FlagSuggestion, + FlagSuggestionAttributes: FlagSuggestionAttributes, + FlagSuggestionResponse: FlagSuggestionResponse, GuardrailMetric: GuardrailMetric, GuardrailMetricRequest: GuardrailMetricRequest, ListAllocationsResponse: ListAllocationsResponse, ListEnvironmentsResponse: ListEnvironmentsResponse, ListFeatureFlagsResponse: ListFeatureFlagsResponse, OverwriteAllocationsRequest: OverwriteAllocationsRequest, + ReviewFlagSuggestionAttributes: ReviewFlagSuggestionAttributes, + ReviewFlagSuggestionData: ReviewFlagSuggestionData, + ReviewFlagSuggestionRequest: ReviewFlagSuggestionRequest, RolloutOptions: RolloutOptions, RolloutOptionsRequest: RolloutOptionsRequest, + SuggestionMetadata: SuggestionMetadata, TargetingRule: TargetingRule, TargetingRuleRequest: TargetingRuleRequest, UpdateEnvironmentAttributes: UpdateEnvironmentAttributes,