-
-
Notifications
You must be signed in to change notification settings - Fork 82
Develop #394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Develop #394
Changes from 3 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
3e1bdc8
Merge pull request #391 from Resgrid/chatbot
ucswift ccf911d
RE1-T120 Feature flag capability
ucswift 5b2faf9
RE1-T120 Cr change
ucswift 6440db9
RE1-T117 PR#394
ucswift ec6cd04
RE1-T117 PR#394 adding feature toggle for chatbot twilio
ucswift 60ff082
RE1-T117 Fixing build
ucswift File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Resgrid.Config | ||
| { | ||
| /// <summary> | ||
| /// Global configuration for the built-in feature toggle subsystem. Loaded by ConfigProcessor via | ||
| /// reflection (keys: "FeatureFlagsConfig.Field" in JSON or "RESGRID:FeatureFlagsConfig:Field" env). | ||
| /// </summary> | ||
| public static class FeatureFlagsConfig | ||
| { | ||
| /// <summary> | ||
| /// Master switch for the whole subsystem. When false, evaluations short-circuit to the | ||
| /// caller-supplied (or code-registered) default and no flag/override data is consulted. | ||
| /// </summary> | ||
| public static bool FeatureFlagsEnabled = true; | ||
|
|
||
| /// <summary> | ||
| /// How long the flag set and per-department overrides are cached. Flag/override writes invalidate | ||
| /// the relevant cache immediately, so this can be generous. | ||
| /// </summary> | ||
| public static int CacheDurationMinutes = 60; | ||
|
|
||
| /// <summary> | ||
| /// When true, evaluations increment in-memory counters that the usage-flush worker persists to | ||
| /// FeatureFlagUsages and uses to refresh LastEvaluatedOn (for stale-flag detection). | ||
| /// </summary> | ||
| public static bool TrackEvaluations = true; | ||
|
|
||
| /// <summary>How often the usage-flush worker drains the in-memory evaluation counters.</summary> | ||
| public static int EvaluationFlushIntervalSeconds = 60; | ||
|
|
||
| /// <summary>Non-permanent flags not evaluated within this many days are reported as stale.</summary> | ||
| public static int StaleFlagThresholdDays = 90; | ||
|
|
||
| /// <summary> | ||
| /// Code-registered boolean defaults keyed by flag key. Used as the fallback when a flag has not | ||
| /// yet been seeded in the database, so new flags behave predictably before they exist as rows. | ||
| /// </summary> | ||
| public static Dictionary<string, bool> CodeDefaults = new Dictionary<string, bool>(); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.ComponentModel.DataAnnotations; | ||
| using System.ComponentModel.DataAnnotations.Schema; | ||
| using Newtonsoft.Json; | ||
| using ProtoBuf; | ||
|
|
||
| namespace Resgrid.Model | ||
| { | ||
| /// <summary> | ||
| /// A system-wide feature flag definition with a global default. Per-department behavior is | ||
| /// layered on top via <see cref="FeatureFlagOverride"/>, <see cref="FeatureFlagTargetingRule"/> | ||
| /// and <see cref="FeatureFlagPrerequisite"/>. | ||
| /// </summary> | ||
| [Table("FeatureFlags")] | ||
| [ProtoContract] | ||
| public class FeatureFlag : IEntity | ||
| { | ||
| [Key] | ||
| [Required] | ||
| [DatabaseGenerated(DatabaseGeneratedOption.Identity)] | ||
| [ProtoMember(1)] | ||
| public int FeatureFlagId { get; set; } | ||
|
|
||
| /// <summary>Stable identifier referenced by code and clients (e.g. "new-dispatch-ui").</summary> | ||
| [Required] | ||
| [ProtoMember(2)] | ||
| public string FlagKey { get; set; } | ||
|
|
||
| [Required] | ||
| [ProtoMember(3)] | ||
| public string Name { get; set; } | ||
|
|
||
| [ProtoMember(4)] | ||
| public string Description { get; set; } | ||
|
|
||
| [ProtoMember(5)] | ||
| public string Category { get; set; } | ||
|
|
||
| /// <summary>Comma-separated free-form tags for grouping/searching.</summary> | ||
| [ProtoMember(6)] | ||
| public string Tags { get; set; } | ||
|
|
||
| /// <summary>Backing int for <see cref="FeatureFlagValueTypes"/>.</summary> | ||
| [Required] | ||
| [ProtoMember(7)] | ||
| public int FlagType { get; set; } | ||
|
|
||
| /// <summary>The global on/off default and application-wide kill switch.</summary> | ||
| [Required] | ||
| [ProtoMember(8)] | ||
| public bool IsEnabledGlobally { get; set; } | ||
|
|
||
| /// <summary>Value returned when the flag resolves "on" for multivariate flags.</summary> | ||
| [ProtoMember(9)] | ||
| public string DefaultValue { get; set; } | ||
|
|
||
| /// <summary>Value returned when the flag resolves "off" for multivariate flags.</summary> | ||
| [ProtoMember(10)] | ||
| public string OffValue { get; set; } | ||
|
|
||
| /// <summary>0-100 gradual rollout across departments when globally on; null = 100%.</summary> | ||
| [ProtoMember(11)] | ||
| public int? RolloutPercentage { get; set; } | ||
|
|
||
| /// <summary>Optional minimum subscription plan id required for the flag to be on.</summary> | ||
| [ProtoMember(12)] | ||
| public int? MinimumPlanType { get; set; } | ||
|
|
||
| /// <summary>Optional environment scope (backing int for SystemEnvironment); null = all.</summary> | ||
| [ProtoMember(13)] | ||
| public int? Environment { get; set; } | ||
|
|
||
| [ProtoMember(14)] | ||
| public DateTime? EnableOn { get; set; } | ||
|
|
||
| [ProtoMember(15)] | ||
| public DateTime? DisableOn { get; set; } | ||
|
|
||
| [Required] | ||
| [ProtoMember(16)] | ||
| public bool IsArchived { get; set; } | ||
|
|
||
| /// <summary>Permanent flags are excluded from stale-flag detection.</summary> | ||
| [Required] | ||
| [ProtoMember(17)] | ||
| public bool IsPermanent { get; set; } | ||
|
|
||
| [ProtoMember(18)] | ||
| public DateTime? LastEvaluatedOn { get; set; } | ||
|
|
||
| [Required] | ||
| [ProtoMember(19)] | ||
| public DateTime CreatedOn { get; set; } | ||
|
|
||
| [ProtoMember(20)] | ||
| public string CreatedByUserId { get; set; } | ||
|
|
||
| [ProtoMember(21)] | ||
| public DateTime? UpdatedOn { get; set; } | ||
|
|
||
| [ProtoMember(22)] | ||
| public string UpdatedByUserId { get; set; } | ||
|
|
||
| [NotMapped] | ||
| [JsonIgnore] | ||
| public object IdValue | ||
| { | ||
| get { return FeatureFlagId; } | ||
| set { FeatureFlagId = (int)value; } | ||
| } | ||
|
|
||
| [NotMapped] | ||
| public string TableName => "FeatureFlags"; | ||
|
|
||
| [NotMapped] | ||
| public string IdName => "FeatureFlagId"; | ||
|
|
||
| [NotMapped] | ||
| public int IdType => 0; | ||
|
|
||
| [NotMapped] | ||
| public IEnumerable<string> IgnoredProperties => new string[] { "IdValue", "IdType", "TableName", "IdName" }; | ||
| } | ||
| } |
24 changes: 24 additions & 0 deletions
24
Core/Resgrid.Model/FeatureToggles/FeatureFlagAttributeTypes.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| namespace Resgrid.Model | ||
| { | ||
| /// <summary> | ||
| /// The department attribute a targeting rule compares against. Resolved lazily (and cached) during | ||
| /// evaluation from the department, its subscription plan, and personnel counts. | ||
| /// </summary> | ||
| public enum FeatureFlagAttributeTypes | ||
| { | ||
| /// <summary>The department's current subscription plan id.</summary> | ||
| PlanType = 0, | ||
| /// <summary>The department's country/region.</summary> | ||
| Country = 1, | ||
| /// <summary>The department's active personnel count.</summary> | ||
| PersonnelCount = 2, | ||
| /// <summary>The department's type (e.g. fire, ems).</summary> | ||
| DepartmentType = 3, | ||
| /// <summary>The department's creation date.</summary> | ||
| CreatedDate = 4, | ||
| /// <summary>The department id itself (allow/deny lists).</summary> | ||
| DepartmentId = 5, | ||
| /// <summary>A caller-supplied custom context value (matched by ComparisonValue key).</summary> | ||
| Custom = 6, | ||
| } | ||
| } |
27 changes: 27 additions & 0 deletions
27
Core/Resgrid.Model/FeatureToggles/FeatureFlagEvaluation.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| namespace Resgrid.Model | ||
| { | ||
| /// <summary> | ||
| /// The resolved state of a feature flag for a specific department, including the reason it | ||
| /// resolved that way. Returned by the feature toggle service and surfaced by the poll API. | ||
| /// </summary> | ||
| public class FeatureFlagEvaluation | ||
| { | ||
| public int FeatureFlagId { get; set; } | ||
|
|
||
| /// <summary>The flag's stable key.</summary> | ||
| public string Key { get; set; } | ||
|
|
||
| public bool IsEnabled { get; set; } | ||
|
|
||
| /// <summary>Resolved value (for multivariate flags); for boolean flags mirrors IsEnabled.</summary> | ||
| public string Value { get; set; } | ||
|
|
||
| public FeatureFlagValueTypes ValueType { get; set; } | ||
|
|
||
| /// <summary>Which rule in the evaluation ladder decided the result.</summary> | ||
| public FeatureFlagEvaluationSource Source { get; set; } | ||
|
|
||
| /// <summary>The targeting rule id when <see cref="Source"/> is TargetingRule.</summary> | ||
| public int? MatchedRuleId { get; set; } | ||
| } | ||
| } |
32 changes: 32 additions & 0 deletions
32
Core/Resgrid.Model/FeatureToggles/FeatureFlagEvaluationSource.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| namespace Resgrid.Model | ||
| { | ||
| /// <summary> | ||
| /// Explains which rule in the evaluation ladder decided a flag's value for a department. Returned | ||
| /// on every evaluation so the poll API and logs can show LaunchDarkly-style "evaluation reasons". | ||
| /// </summary> | ||
| public enum FeatureFlagEvaluationSource | ||
| { | ||
| /// <summary>No flag with the requested key exists.</summary> | ||
| NotFound = 0, | ||
| /// <summary>Value came from a code-registered default in FeatureFlagsConfig.</summary> | ||
| CodeDefault = 1, | ||
| /// <summary>The whole feature-toggle subsystem is disabled via config.</summary> | ||
| SubsystemDisabled = 2, | ||
| /// <summary>The flag is archived.</summary> | ||
| Archived = 3, | ||
| /// <summary>Decided by the flag's scheduled enable/disable window.</summary> | ||
| Schedule = 4, | ||
| /// <summary>A prerequisite flag was not satisfied.</summary> | ||
| Prerequisite = 5, | ||
| /// <summary>An explicit per-department override decided the value.</summary> | ||
| Override = 6, | ||
| /// <summary>The department's subscription plan did not meet the flag's minimum plan.</summary> | ||
| PlanGate = 7, | ||
| /// <summary>A matching attribute/segment targeting rule decided the value.</summary> | ||
| TargetingRule = 8, | ||
| /// <summary>Decided by the global default and the percentage rollout bucket.</summary> | ||
| GlobalRollout = 9, | ||
| /// <summary>Decided by the global default (fully on/off, no rollout in effect).</summary> | ||
| GlobalDefault = 10, | ||
| } | ||
| } |
19 changes: 19 additions & 0 deletions
19
Core/Resgrid.Model/FeatureToggles/FeatureFlagOperatorTypes.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| namespace Resgrid.Model | ||
| { | ||
| /// <summary> | ||
| /// The comparison applied by a targeting rule between a department attribute and the rule's | ||
| /// ComparisonValue. In/NotIn treat ComparisonValue as a comma-separated list. | ||
| /// </summary> | ||
| public enum FeatureFlagOperatorTypes | ||
| { | ||
| Equals = 0, | ||
| NotEquals = 1, | ||
| In = 2, | ||
| NotIn = 3, | ||
| GreaterThan = 4, | ||
| GreaterThanOrEqual = 5, | ||
| LessThan = 6, | ||
| LessThanOrEqual = 7, | ||
| Contains = 8, | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.ComponentModel.DataAnnotations; | ||
| using System.ComponentModel.DataAnnotations.Schema; | ||
| using Newtonsoft.Json; | ||
| using ProtoBuf; | ||
|
|
||
| namespace Resgrid.Model | ||
| { | ||
| /// <summary> | ||
| /// A per-department override of a feature flag's value. An explicit, non-expired override takes | ||
| /// precedence over rollout and targeting rules. | ||
| /// </summary> | ||
| [Table("FeatureFlagOverrides")] | ||
| [ProtoContract] | ||
| public class FeatureFlagOverride : IEntity | ||
| { | ||
| [Key] | ||
| [Required] | ||
| [DatabaseGenerated(DatabaseGeneratedOption.Identity)] | ||
| [ProtoMember(1)] | ||
| public int FeatureFlagOverrideId { get; set; } | ||
|
|
||
| [Required] | ||
| [ProtoMember(2)] | ||
| public int FeatureFlagId { get; set; } | ||
|
|
||
| [Required] | ||
| [ProtoMember(3)] | ||
| public int DepartmentId { get; set; } | ||
|
|
||
| [Required] | ||
| [ProtoMember(4)] | ||
| public bool IsEnabled { get; set; } | ||
|
|
||
| /// <summary>Override variant value for multivariate flags.</summary> | ||
| [ProtoMember(5)] | ||
| public string FlagValue { get; set; } | ||
|
|
||
| [ProtoMember(6)] | ||
| public string Reason { get; set; } | ||
|
|
||
| /// <summary>Optional expiry after which the override is ignored.</summary> | ||
| [ProtoMember(7)] | ||
| public DateTime? ExpiresOn { get; set; } | ||
|
|
||
| [Required] | ||
| [ProtoMember(8)] | ||
| public DateTime CreatedOn { get; set; } | ||
|
|
||
| [ProtoMember(9)] | ||
| public string CreatedByUserId { get; set; } | ||
|
|
||
| [ProtoMember(10)] | ||
| public DateTime? UpdatedOn { get; set; } | ||
|
|
||
| [ProtoMember(11)] | ||
| public string UpdatedByUserId { get; set; } | ||
|
|
||
| [NotMapped] | ||
| [JsonIgnore] | ||
| public object IdValue | ||
| { | ||
| get { return FeatureFlagOverrideId; } | ||
| set { FeatureFlagOverrideId = (int)value; } | ||
| } | ||
|
|
||
| [NotMapped] | ||
| public string TableName => "FeatureFlagOverrides"; | ||
|
|
||
| [NotMapped] | ||
| public string IdName => "FeatureFlagOverrideId"; | ||
|
|
||
| [NotMapped] | ||
| public int IdType => 0; | ||
|
|
||
| [NotMapped] | ||
| public IEnumerable<string> IgnoredProperties => new string[] { "IdValue", "IdType", "TableName", "IdName" }; | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.