Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export const featureFlagPrefix = ".appconfig.featureflag/";

// @public
export interface FeatureFlagValue {
conditions: {
conditions?: {
clientFilters: {
name: string;
parameters?: Record<string, unknown>;
Expand All @@ -145,7 +145,7 @@ export interface FeatureFlagValue {
};
description?: string;
displayName?: string;
enabled: boolean;
enabled?: boolean;
id?: string;
}

Expand Down
29 changes: 19 additions & 10 deletions sdk/appconfiguration/app-configuration/src/featureFlag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export interface FeatureFlagValue {
*
* [More Info](https://learn.microsoft.com/azure/azure-app-configuration/howto-feature-filters-aspnet-core)
*/
conditions: {
conditions?: {
clientFilters: { name: string; parameters?: Record<string, unknown> }[];
requirementType?: "All" | "Any";
};
Expand All @@ -41,7 +41,7 @@ export interface FeatureFlagValue {
/**
* Boolean flag to say if the feature flag is enabled.
*/
enabled: boolean;
enabled?: boolean;
/**
* Display name for the feature to use for display rather than the ID.
*/
Expand Down Expand Up @@ -69,14 +69,18 @@ export const FeatureFlagHelper = {
}
const jsonFeatureFlagValue: JsonFeatureFlagValue = {
id: featureFlag.value.id ?? key.replace(featureFlagPrefix, ""),
enabled: featureFlag.value.enabled,
enabled: featureFlag.value.enabled ?? false,
description: featureFlag.value.description,
conditions: {
};

if (featureFlag.value.conditions) {
jsonFeatureFlagValue.conditions = {
client_filters: featureFlag.value.conditions.clientFilters,
requirement_type: featureFlag.value.conditions.requirementType ?? "Any",
},
display_name: featureFlag.value.displayName,
};
};
}

jsonFeatureFlagValue.display_name = featureFlag.value.displayName;

const configSetting = {
...featureFlag,
Expand Down Expand Up @@ -114,14 +118,19 @@ export function parseFeatureFlag(
enabled: jsonFeatureFlagValue.enabled,
description: jsonFeatureFlagValue.description,
displayName: jsonFeatureFlagValue.display_name,
conditions: { clientFilters: jsonFeatureFlagValue.conditions.client_filters },
},
key,
contentType: featureFlagContentType,
};

if (jsonFeatureFlagValue.conditions.requirement_type) {
featureflag.value.conditions.requirementType = jsonFeatureFlagValue.conditions.requirement_type;
if (jsonFeatureFlagValue.conditions) {
featureflag.value.conditions = {
clientFilters: jsonFeatureFlagValue.conditions.client_filters,
};
if (jsonFeatureFlagValue.conditions.requirement_type) {
featureflag.value.conditions.requirementType =
jsonFeatureFlagValue.conditions.requirement_type;
}
}
return featureflag;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
* @internal
*/
export type JsonFeatureFlagValue = {
conditions: {
conditions?: {
client_filters: { name: string; parameters?: Record<string, unknown> }[];
requirement_type?: "All" | "Any";
};
description?: string;
enabled: boolean;
enabled?: boolean;
id?: string;
display_name?: string;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import type { ConfigurationSetting } from "../../src/index.js";
import { featureFlagContentType } from "../../src/index.js";
import { parseFeatureFlag } from "../../src/featureFlag.js";
import { describe, it, assert } from "vitest";

describe("FeatureFlag - Optional Fields", () => {
it("should parse feature flag with only id field", () => {
const minimalFeatureFlag = {
key: ".appconfig.featureflag/minimal-flag",
value: JSON.stringify({ id: "minimal-flag" }),
contentType: featureFlagContentType,
} as ConfigurationSetting;

const parsed = parseFeatureFlag(minimalFeatureFlag);
assert.equal(parsed.value.id, "minimal-flag");
assert.isUndefined(parsed.value.enabled);
assert.isUndefined(parsed.value.conditions);
assert.isUndefined(parsed.value.description);
assert.isUndefined(parsed.value.displayName);
});

it("should parse feature flag without conditions", () => {
const featureFlagWithoutConditions = {
key: ".appconfig.featureflag/no-conditions",
value: JSON.stringify({
id: "no-conditions",
enabled: true,
description: "A feature flag without conditions",
display_name: "No Conditions Flag",
}),
contentType: featureFlagContentType,
} as ConfigurationSetting;

const parsed = parseFeatureFlag(featureFlagWithoutConditions);
assert.equal(parsed.value.id, "no-conditions");
assert.equal(parsed.value.enabled, true);
assert.equal(parsed.value.description, "A feature flag without conditions");
assert.equal(parsed.value.displayName, "No Conditions Flag");
assert.isUndefined(parsed.value.conditions);
});

it("should parse feature flag with empty conditions", () => {
const featureFlagWithEmptyConditions = {
key: ".appconfig.featureflag/empty-conditions",
value: JSON.stringify({
id: "empty-conditions",
enabled: false,
conditions: {
client_filters: [],
},
}),
contentType: featureFlagContentType,
} as ConfigurationSetting;

const parsed = parseFeatureFlag(featureFlagWithEmptyConditions);
assert.equal(parsed.value.id, "empty-conditions");
assert.equal(parsed.value.enabled, false);
assert.isDefined(parsed.value.conditions);
assert.deepEqual(parsed.value.conditions?.clientFilters, []);
assert.isUndefined(parsed.value.conditions?.requirementType);
});

it("should parse feature flag with conditions and requirement_type", () => {
const fullFeatureFlag = {
key: ".appconfig.featureflag/full-flag",
value: JSON.stringify({
id: "full-flag",
enabled: true,
description: "Full feature flag",
display_name: "Full Flag",
conditions: {
client_filters: [{ name: "Filter1", parameters: { key: "value" } }, { name: "Filter2" }],
requirement_type: "All",
},
}),
contentType: featureFlagContentType,
} as ConfigurationSetting;

const parsed = parseFeatureFlag(fullFeatureFlag);
assert.equal(parsed.value.id, "full-flag");
assert.equal(parsed.value.enabled, true);
assert.equal(parsed.value.description, "Full feature flag");
assert.equal(parsed.value.displayName, "Full Flag");
assert.isDefined(parsed.value.conditions);
assert.equal(parsed.value.conditions?.clientFilters.length, 2);
assert.equal(parsed.value.conditions?.requirementType, "All");
});
});