Skip to content

Commit 1a9bc8c

Browse files
authored
feat(ui/dashboard): feature flag list page (#1600)
1 parent 924163a commit 1a9bc8c

File tree

104 files changed

+4657
-157
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+4657
-157
lines changed

ui/dashboard/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@
5454
"prettier": "^3.3.3",
5555
"query-string": "^9.1.0",
5656
"react": "^18.3.1",
57-
"react-datepicker": "^7.6.0",
5857
"react-chartjs-2": "^5.3.0",
58+
"react-datepicker": "^7.6.0",
5959
"react-dom": "^18.3.1",
6060
"react-easy-crop": "^5.2.0",
6161
"react-error-boundary": "^4.0.13",
@@ -96,6 +96,7 @@
9696
"postcss": "^8.4.41",
9797
"prettier-plugin-tailwindcss": "^0.6.5",
9898
"react-hot-toast": "^2.4.1",
99+
"react-responsive": "^10.0.1",
99100
"svgo": "^3.3.2",
100101
"tailwindcss": "^3.4.9",
101102
"typescript": "^5.5.3",

ui/dashboard/public/locales/en/common.json

+20-1
Original file line numberDiff line numberDiff line change
@@ -190,5 +190,24 @@
190190
"try-again": "Try again"
191191
},
192192
"select": "Select",
193-
"switch-organization": "Switch organization"
193+
"switch-organization": "Switch organization",
194+
"feature-flags": "Feature Flags",
195+
"feature-flags-subtitle": "Select a flag to configure targeting, manage rollout strategies, and control feature availability.",
196+
"new-flag": "New Feature Flag",
197+
"operations": "Operations",
198+
"favorites": "Favorites",
199+
"no-variations": "No Variations",
200+
"new": "New",
201+
"no-activity": "No Activity",
202+
"notifications": "Notifications",
203+
"create-flag": "Create Flag",
204+
"clone-flag": "Clone Flag",
205+
"archive-flag": "Archive Flag",
206+
"unarchive-flag": "Unarchive Flag",
207+
"update-now": "Update now",
208+
"time-updated": "Updated {{time}}",
209+
"default": "Default",
210+
"sort-by": "Sort by: {{sortBy}}",
211+
"sort-asc": "Oldest to Newest",
212+
"sort-desc": "Newest to Oldest"
194213
}

ui/dashboard/public/locales/en/form.json

+37-1
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,41 @@
115115
"member-tags-tooltip": "Tags can be used to group members making it easier when listing them on the list page",
116116
"feature-flag-tags": "Feature Flag Tags",
117117
"no-tags-found": "No tags were found",
118-
"placeholder-search": "Search"
118+
"placeholder-search": "Search",
119+
"feature-flags": {
120+
"clone-title": "Clone Feature Flag",
121+
"clone-desc": "It will copy the full targeting configuration, including on/off variation from the original flag to the new flag.",
122+
"flag-id": "Flag ID",
123+
"placeholder-flag": "Enter flag id",
124+
"flag-variations": "Flag Variations",
125+
"flag-type": "Flag Type",
126+
"variation": "Variation {{index}}",
127+
"add-variation": "Add Variation",
128+
"serve-targeting": "Serve when targeting is {{state}}",
129+
"placeholder-variation": "Enter variation value",
130+
"active-now": "Active now",
131+
"schedule": "Schedule",
132+
"start-at": "Start at",
133+
"situation": "Situation",
134+
"conditioner": "Conditioner",
135+
"value-type": "{{type}} Value",
136+
"date": "Date",
137+
"compare": "Compare",
138+
"user-segment": "User Segment",
139+
"feature-flag": "Feature Flag",
140+
"add-condition": "Add Condition",
141+
"value": "Value",
142+
"receiving-state": "is {{state}} and receiving",
143+
"flag": "Flag",
144+
"prerequisites": "Prerequisites",
145+
"add-prerequisites": "Add Prerequisites",
146+
"disable-now": "Disable now",
147+
"schedule-info": "You can update or delete the schedule on the Auto Operations tab on the Feature Flag details page.",
148+
"flag-switch": "{{name}} has been {{state}}.",
149+
"schedule-configured": "Schedule has been configured for {{name}}."
150+
},
151+
"origin-env": "Origin Environment",
152+
"destination-env": "Destination Environment",
153+
"comment-for-update": "Comment for update",
154+
"placeholder-comment": "Enter comment"
119155
}

ui/dashboard/public/locales/en/table.json

+42-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@
3535
"archive-experiment": "Archive Experiment",
3636
"unarchive-experiment": "Unarchive Experiment",
3737
"stop-experiment": "Stop Experiment",
38-
"start-experiment": "Start Experiment"
38+
"start-experiment": "Start Experiment",
39+
"archive-flag": "Archive Feature Flag",
40+
"unarchive-flag": "Unarchive Feature Flag",
41+
"clone-flag": "Clone Feature Flag"
3942
},
4043
"empty": {
4144
"project-title": "No registered projects",
@@ -59,7 +62,10 @@
5962
"user-segments-desc": "There are no registered user segments. Add a new one to start managing.",
6063
"experiment-title": "No registered experiments",
6164
"experiment-desc": "There are no registered experiments. Add a new one to start managing.",
62-
"experiment-details-desc": "The result will be created when the experiment starts."
65+
"experiment-details-desc": "The result will be created when the experiment starts.",
66+
"feature-flags-title": "No registered feature flags",
67+
"feature-flags-desc": "There are no registered feature flags. Add a new one to start managing.",
68+
"notifications": "No notifications to show just yet, but don't worry, we're here to keep you in the loop."
6369
},
6470
"organization": {
6571
"confirm-archive-desc": "The organization \"<bold>{{name}}</bold>\" will be archived. Are you sure you want to proceed?",
@@ -138,5 +144,39 @@
138144
"improvement-tooltip": "A measure of improvement in an indicator related to variation compared to a baseline (also called a control group). It is calculated by comparing the range of values for variation with the range of values for baseline.",
139145
"probability-to-beat-baseline-tooltip": "Estimated likelihood of exceeding baseline (also known as a control group). A criterion of at least 95% is recommended.",
140146
"probability-to-best-tooltip": "Possibility of being the best variation. Possibility of being presumed to outperform all other variations. We recommend a criterion of at least 95%."
147+
},
148+
"feature-flags": {
149+
"confirm-archive-desc": "This will archive and return the default value defined in your code for all users. We recommend removing the code references to \"<text>{{name}}</text>\" from your application before archiving.",
150+
"confirm-unarchive-desc": "Are you sure you want to unarchive the feature flag \"<text>{{name}}</text>\"?",
151+
"archive-warning": "It is receiving one more requests in the last <text>{{days}}.</text>",
152+
"confirm-required": "Confirmation Required",
153+
"confirm-required-desc": "This will make changes to the flag and increment the version.",
154+
"targeting": "Targeting",
155+
"variation": "Variation",
156+
"evaluation": "Evaluation",
157+
"operations": "Operations",
158+
"trigger": "Trigger",
159+
"experiments": "Experiments",
160+
"history": "History",
161+
"when-targeting": "When targeting is {{state}}",
162+
"serve": "Serve",
163+
"add-rule": "Add Rule",
164+
"target-segments": "Target Segments",
165+
"target-individuals": "Target Individuals",
166+
"set-prerequisites": "Set Prerequisites",
167+
"default-rule": "Default Rule",
168+
"default-rule-desc": "When targeting is ON and contexts don't match any targeting rules",
169+
"rules": "Rules",
170+
"rule-index": "Rule {{index}}",
171+
"total-flags": "Total Flags",
172+
"active-flags": "Active Flags",
173+
"inactive-flags": "Inactive Flags",
174+
"variation-type": "<text>{{type}}</text> variation type",
175+
"active-description": "This flag is receiving one or more requests in the last 7 days",
176+
"inactive-description": "This flag hasn't received any request in the last 7 days",
177+
"new-description": "This flag didn't receive any request after creation",
178+
"progressive-description": "This flag has a progressive rollout.",
179+
"scheduled-description": "This flag has a scheduled operation.",
180+
"kill-description": "This flag has an automatic kill switch."
141181
}
142182
}

ui/dashboard/public/locales/ja/common.json

+18-1
Original file line numberDiff line numberDiff line change
@@ -190,5 +190,22 @@
190190
"try-again": "Try again"
191191
},
192192
"select": "Select",
193-
"switch-organization": "Switch organization"
193+
"switch-organization": "Switch organization",
194+
"feature-flags": "Feature Flags",
195+
"feature-flags-subtitle": "Select a flag to configure targeting, manage rollout strategies, and control feature availability.",
196+
"new-flag": "New Feature Flag",
197+
"operations": "Operations",
198+
"favorites": "Favorites",
199+
"no-variations": "No Variations",
200+
"new": "New",
201+
"no-activity": "No Activity",
202+
"notifications": "Notifications",
203+
"create-flag": "Create Flag",
204+
"clone-flag": "Clone Flag",
205+
"archive-flag": "Archive Flag",
206+
"unarchive-flag": "Unarchive Flag",
207+
"update-now": "Update now",
208+
"time-updated": "Updated {{time}}",
209+
"default": "Default",
210+
"sort-by": "Sort by: {{sortBy}}"
194211
}

ui/dashboard/public/locales/ja/form.json

+37-1
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,41 @@
115115
"member-tags-tooltip": "Tags can be used to group members making it easier when listing them on the list page",
116116
"feature-flag-tags": "Feature Flag Tags",
117117
"no-tags-found": "No tags were found",
118-
"placeholder-search": "Search"
118+
"placeholder-search": "Search",
119+
"feature-flags": {
120+
"clone-title": "Clone Feature Flag",
121+
"clone-desc": "It will copy the full targeting configuration, including on/off variation from the original flag to the new flag.",
122+
"flag-id": "Flag ID",
123+
"placeholder-flag": "Enter flag id",
124+
"flag-variations": "Flag Variations",
125+
"flag-type": "Flag Type",
126+
"variation": "Variation {{index}}",
127+
"add-variation": "Add Variation",
128+
"serve-targeting": "Serve when targeting is {{state}}",
129+
"placeholder-variation": "Enter variation value",
130+
"active-now": "Active now",
131+
"schedule": "Schedule",
132+
"start-at": "Start at",
133+
"situation": "Situation",
134+
"conditioner": "Conditioner",
135+
"value-type": "{{type}} Value",
136+
"date": "Date",
137+
"compare": "Compare",
138+
"user-segment": "User Segment",
139+
"feature-flag": "Feature Flag",
140+
"add-condition": "Add Condition",
141+
"value": "Value",
142+
"receiving-state": "is {{state}} and receiving",
143+
"flag": "Flag",
144+
"prerequisites": "Prerequisites",
145+
"add-prerequisites": "Add Prerequisites",
146+
"disable-now": "Disable now",
147+
"schedule-info": "You can update or delete the schedule on the Auto Operations tab on the Feature Flag details page.",
148+
"flag-switch": "{{name}} has been {{state}}.",
149+
"schedule-configured": "Schedule has been configured for {{name}}."
150+
},
151+
"origin-env": "Origin Environment",
152+
"destination-env": "Destination Environment",
153+
"comment-for-update": "Comment for update",
154+
"placeholder-comment": "Enter comment"
119155
}

ui/dashboard/public/locales/ja/table.json

+46-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@
3535
"archive-experiment": "Archive Experiment",
3636
"unarchive-experiment": "Unarchive Experiment",
3737
"stop-experiment": "Stop Experiment",
38-
"start-experiment": "Start Experiment"
38+
"start-experiment": "Start Experiment",
39+
"archive-flag": "Archive Feature Flag",
40+
"unarchive-flag": "Unarchive Feature Flag",
41+
"clone-flag": "Clone Feature Flag"
3942
},
4043
"empty": {
4144
"project-title": "No registered projects",
@@ -59,7 +62,10 @@
5962
"user-segments-desc": "There are no registered user segments. Add a new one to start managing.",
6063
"experiment-title": "No registered experiments",
6164
"experiment-desc": "There are no registered experiments. Add a new one to start managing.",
62-
"experiment-details-desc": "The result will be created when the experiment starts."
65+
"experiment-details-desc": "The result will be created when the experiment starts.",
66+
"feature-flags-title": "No registered feature flags",
67+
"feature-flags-desc": "There are no registered feature flags. Add a new one to start managing.",
68+
"notifications": "No notifications to show just yet, but don't worry, we're here to keep you in the loop."
6369
},
6470
"organization": {
6571
"confirm-archive-desc": "The organization \"<bold>{{name}}</bold>\" will be archived. Are you sure you want to proceed?",
@@ -107,6 +113,10 @@
107113
"running": "Running",
108114
"stopped": "Stopped",
109115
"not-started": "Not started",
116+
"scheduled-experiment": "Scheduled Experiment",
117+
"running-experiment": "Running Experiment",
118+
"stopped-experiment": "Stopped Experiment",
119+
"not-started-experiment": "Not Started Experiment",
110120
"confirm-stop-desc": "The experiment \"<bold>{{name}}</bold>\" will be stopped. Are you sure you want to proceed?",
111121
"confirm-start-desc": "The experiment \"<bold>{{name}}</bold>\" will be started. Are you sure you want to proceed?",
112122
"running-experiment-desc": "The experiment is scheduled to stop on {{date}}",
@@ -134,5 +144,39 @@
134144
"improvement-tooltip": "A measure of improvement in an indicator related to variation compared to a baseline (also called a control group). It is calculated by comparing the range of values for variation with the range of values for baseline.",
135145
"probability-to-beat-baseline-tooltip": "Estimated likelihood of exceeding baseline (also known as a control group). A criterion of at least 95% is recommended.",
136146
"probability-to-best-tooltip": "Possibility of being the best variation. Possibility of being presumed to outperform all other variations. We recommend a criterion of at least 95%."
147+
},
148+
"feature-flags": {
149+
"confirm-archive-desc": "This will archive and return the default value defined in your code for all users. We recommend removing the code references to \"<text>{{name}}</text>\" from your application before archiving.",
150+
"confirm-unarchive-desc": "Are you sure you want to unarchive the feature flag \"<text>{{name}}</text>\"?",
151+
"archive-warning": "It is receiving one more requests in the last <text>{{days}}.</text>",
152+
"confirm-required": "Confirmation Required",
153+
"confirm-required-desc": "This will make changes to the flag and increment the version.",
154+
"targeting": "Targeting",
155+
"variation": "Variation",
156+
"evaluation": "Evaluation",
157+
"operations": "Operations",
158+
"trigger": "Trigger",
159+
"experiments": "Experiments",
160+
"history": "History",
161+
"when-targeting": "When targeting is {{state}}",
162+
"serve": "Serve",
163+
"add-rule": "Add Rule",
164+
"target-segments": "Target Segments",
165+
"target-individuals": "Target Individuals",
166+
"set-prerequisites": "Set Prerequisites",
167+
"default-rule": "Default Rule",
168+
"default-rule-desc": "When targeting is ON and contexts don't match any targeting rules",
169+
"rules": "Rules",
170+
"rule-index": "Rule {{index}}",
171+
"total-flags": "Total Flags",
172+
"active-flags": "Active Flags",
173+
"inactive-flags": "Inactive Flags",
174+
"variation-type": "<text>{{type}}</text> variation type",
175+
"active-description": "This flag is receiving one or more requests in the last 7 days",
176+
"inactive-description": "This flag hasn't received any request in the last 7 days",
177+
"new-description": "This flag didn't receive any request after creation",
178+
"progressive-description": "This flag has a progressive rollout.",
179+
"scheduled-description": "This flag has a scheduled operation.",
180+
"kill-description": "This flag has an automatic kill switch."
137181
}
138182
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import axiosClient from '@api/axios-client';
2+
import {
3+
AutoOpsRule,
4+
AutoOpsType,
5+
DatetimeClause,
6+
OpsEventRateClause
7+
} from '@types';
8+
9+
export interface AutoOpsCreatorParams {
10+
environmentId: string;
11+
featureId: string;
12+
opsType: AutoOpsType;
13+
opsEventRateClauses?: OpsEventRateClause[];
14+
datetimeClauses?: DatetimeClause[];
15+
}
16+
17+
export interface AutoOpsCreatorResponse {
18+
autoOpsRule: AutoOpsRule;
19+
}
20+
21+
export const autoOpsCreator = async (
22+
params?: AutoOpsCreatorParams
23+
): Promise<AutoOpsCreatorResponse> => {
24+
return axiosClient
25+
.post<AutoOpsCreatorResponse>('/v1/auto_ops_rule', params)
26+
.then(response => response.data);
27+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import axiosClient from '@api/axios-client';
2+
import pickBy from 'lodash/pickBy';
3+
import { CollectionParams, AutoOpsRuleCollection } from '@types';
4+
import { isNotEmpty } from 'utils/data-type';
5+
import { stringifyParams } from 'utils/search-params';
6+
7+
export interface AutoOpsFetcherParams extends CollectionParams {
8+
environmentId: string;
9+
featureIds?: string[];
10+
}
11+
12+
export const autoOpsFetcher = async (
13+
_params?: AutoOpsFetcherParams
14+
): Promise<AutoOpsRuleCollection> => {
15+
const params = pickBy(_params, v => isNotEmpty(v));
16+
17+
return axiosClient
18+
.get<AutoOpsRuleCollection>(`/v1/auto_ops_rules?${stringifyParams(params)}`)
19+
.then(response => response.data);
20+
};
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './auto-ops-fetcher';
2+
export * from './auto-ops-creator';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import axiosClient from '@api/axios-client';
2+
import { Feature } from '@types';
3+
4+
export interface FeatureCloneParams {
5+
id: string;
6+
environmentId: string;
7+
targetEnvironmentId: string;
8+
}
9+
10+
export interface FeatureResponse {
11+
feature: Feature;
12+
}
13+
14+
export const featureClone = async (
15+
params?: FeatureCloneParams
16+
): Promise<FeatureResponse> => {
17+
return axiosClient
18+
.post<FeatureResponse>(`/v1/feature/clone`, params)
19+
.then(response => response.data);
20+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import axiosClient from '@api/axios-client';
2+
import { Feature, FeatureVariation, FeatureVariationType } from '@types';
3+
4+
export interface FeatureCreatorParams {
5+
environmentId: string;
6+
id: string;
7+
name: string;
8+
variations: FeatureVariation[];
9+
tags: string[];
10+
defaultOnVariationIndex: number;
11+
defaultOffVariationIndex: number;
12+
variationType: FeatureVariationType;
13+
description?: string;
14+
}
15+
16+
export interface FeatureCreatorResponse {
17+
feature: Feature;
18+
}
19+
20+
export const featureCreator = async (
21+
params?: FeatureCreatorParams
22+
): Promise<FeatureCreatorResponse> => {
23+
return axiosClient
24+
.post<FeatureCreatorResponse>('/v1/feature', params)
25+
.then(response => response.data);
26+
};

0 commit comments

Comments
 (0)