@featurevisor/site 1.29.2 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/App.tsx +15 -3
- package/src/components/ShowFeature.tsx +61 -46
- package/src/utils/index.ts +26 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@featurevisor/site",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.0",
|
|
4
4
|
"description": "Static site for Featurevisor",
|
|
5
5
|
"main": "dist",
|
|
6
6
|
"scripts": {
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"webpack-merge": "^5.10.0"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@featurevisor/types": "1.
|
|
62
|
+
"@featurevisor/types": "1.32.0"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "c360fac0c91b586847633c2d41cf5e4d6922a9b8"
|
|
65
65
|
}
|
package/src/components/App.tsx
CHANGED
|
@@ -50,7 +50,7 @@ export function App() {
|
|
|
50
50
|
}, []);
|
|
51
51
|
|
|
52
52
|
const environmentKeys = fetchedSearchIndex
|
|
53
|
-
?
|
|
53
|
+
? (fetchedSearchIndex as SearchIndex).projectConfig.environments
|
|
54
54
|
: [];
|
|
55
55
|
|
|
56
56
|
return (
|
|
@@ -72,11 +72,23 @@ export function App() {
|
|
|
72
72
|
<Route path="variables" element={<DisplayFeatureVariablesSchema />} />
|
|
73
73
|
<Route path="rules" element={<DisplayFeatureRules />}>
|
|
74
74
|
<Route path=":environmentKey" element={<DisplayFeatureRulesTable />} />
|
|
75
|
-
<Route
|
|
75
|
+
<Route
|
|
76
|
+
index
|
|
77
|
+
element={
|
|
78
|
+
Array.isArray(environmentKeys) &&
|
|
79
|
+
environmentKeys.length > 0 && <Navigate to={environmentKeys[0]} replace />
|
|
80
|
+
}
|
|
81
|
+
/>
|
|
76
82
|
</Route>
|
|
77
83
|
<Route path="force" element={<DisplayFeatureForce />}>
|
|
78
84
|
<Route path=":environmentKey" element={<DisplayFeatureForceTable />} />
|
|
79
|
-
<Route
|
|
85
|
+
<Route
|
|
86
|
+
index
|
|
87
|
+
element={
|
|
88
|
+
Array.isArray(environmentKeys) &&
|
|
89
|
+
environmentKeys.length > 0 && <Navigate to={environmentKeys[0]} replace />
|
|
90
|
+
}
|
|
91
|
+
/>
|
|
80
92
|
</Route>
|
|
81
93
|
<Route path="history" element={<DisplayFeatureHistory />} />
|
|
82
94
|
</Route>
|
|
@@ -16,7 +16,7 @@ import { Markdown } from "./Markdown";
|
|
|
16
16
|
export function DisplayFeatureOverview() {
|
|
17
17
|
const { feature } = useOutletContext() as any;
|
|
18
18
|
|
|
19
|
-
const environmentKeys = Object.keys(feature.environments).sort();
|
|
19
|
+
const environmentKeys = feature.environments ? Object.keys(feature.environments).sort() : [];
|
|
20
20
|
|
|
21
21
|
const renderBucketBy = (bucketBy) => {
|
|
22
22
|
if (typeof bucketBy === "string") {
|
|
@@ -110,11 +110,10 @@ export function DisplayFeatureForceTable() {
|
|
|
110
110
|
const { feature } = useOutletContext() as any;
|
|
111
111
|
const { environmentKey } = useParams();
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
) {
|
|
113
|
+
const envKey = environmentKey as string;
|
|
114
|
+
const force = feature.environments ? feature.environments[envKey].force : feature.force;
|
|
115
|
+
|
|
116
|
+
if (!force || force.length === 0) {
|
|
118
117
|
return <p>n/a</p>;
|
|
119
118
|
}
|
|
120
119
|
|
|
@@ -135,7 +134,7 @@ export function DisplayFeatureForceTable() {
|
|
|
135
134
|
</thead>
|
|
136
135
|
|
|
137
136
|
<tbody>
|
|
138
|
-
{
|
|
137
|
+
{force.map((force, index) => {
|
|
139
138
|
return (
|
|
140
139
|
<tr key={index} className={index % 2 === 0 ? undefined : "bg-gray-50"}>
|
|
141
140
|
<td className="py-4 pl-4 pr-3 text-sm text-gray-900">
|
|
@@ -185,7 +184,7 @@ export function DisplayFeatureForceTable() {
|
|
|
185
184
|
|
|
186
185
|
export function DisplayFeatureForce() {
|
|
187
186
|
const { feature } = useOutletContext() as any;
|
|
188
|
-
const environmentKeys = Object.keys(feature.environments).sort();
|
|
187
|
+
const environmentKeys = feature.environments ? Object.keys(feature.environments).sort() : [];
|
|
189
188
|
|
|
190
189
|
const environmentTabs = environmentKeys.map((environmentKey) => {
|
|
191
190
|
return {
|
|
@@ -196,23 +195,29 @@ export function DisplayFeatureForce() {
|
|
|
196
195
|
|
|
197
196
|
return (
|
|
198
197
|
<>
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
198
|
+
{environmentKeys.length > 0 && (
|
|
199
|
+
<nav className="flex space-x-4" aria-label="Tabs">
|
|
200
|
+
{environmentTabs.map((tab) => (
|
|
201
|
+
<NavLink
|
|
202
|
+
key={tab.title}
|
|
203
|
+
to={tab.to}
|
|
204
|
+
className={({ isActive }) =>
|
|
205
|
+
[
|
|
206
|
+
isActive ? "bg-gray-200 text-gray-800" : "text-gray-600 hover:text-gray-800",
|
|
207
|
+
"rounded-md px-3 py-2 text-sm font-medium",
|
|
208
|
+
].join(" ")
|
|
209
|
+
}
|
|
210
|
+
>
|
|
211
|
+
{tab.title}
|
|
212
|
+
</NavLink>
|
|
213
|
+
))}
|
|
214
|
+
</nav>
|
|
215
|
+
)}
|
|
216
|
+
|
|
217
|
+
{/* no environments */}
|
|
218
|
+
{environmentKeys.length === 0 && <DisplayFeatureForceTable />}
|
|
215
219
|
|
|
220
|
+
{/* with environments */}
|
|
216
221
|
<Outlet context={{ feature }} />
|
|
217
222
|
</>
|
|
218
223
|
);
|
|
@@ -222,23 +227,27 @@ export function DisplayFeatureRulesTable() {
|
|
|
222
227
|
const { feature } = useOutletContext() as any;
|
|
223
228
|
const { environmentKey } = useParams();
|
|
224
229
|
|
|
225
|
-
|
|
230
|
+
const envKey = environmentKey as string;
|
|
231
|
+
const rules = feature.environments ? feature.environments[envKey].rules : feature.rules;
|
|
232
|
+
const expose = feature.environments ? feature.environments[envKey].expose : feature.expose;
|
|
233
|
+
|
|
234
|
+
if (!rules || rules.length === 0) {
|
|
226
235
|
return <p>n/a</p>;
|
|
227
236
|
}
|
|
228
237
|
|
|
229
238
|
return (
|
|
230
239
|
<div>
|
|
231
|
-
{
|
|
240
|
+
{expose === false && (
|
|
232
241
|
<p className="mt-2 block rounded border-2 border-orange-300 bg-orange-200 p-3 text-sm text-gray-600">
|
|
233
242
|
Rules are not <a href="https://featurevisor.com/docs/features/#expose">exposed</a> in this
|
|
234
243
|
environment.
|
|
235
244
|
</p>
|
|
236
245
|
)}
|
|
237
246
|
|
|
238
|
-
{Array.isArray(
|
|
247
|
+
{Array.isArray(expose) && (
|
|
239
248
|
<p className="mt-2 block rounded border-2 border-orange-300 bg-orange-200 p-3 text-sm text-gray-600">
|
|
240
249
|
Rules are <a href="https://featurevisor.com/docs/features/#expose">exposed</a> for these
|
|
241
|
-
tags only: {
|
|
250
|
+
tags only: {expose.join(", ")}.
|
|
242
251
|
</p>
|
|
243
252
|
)}
|
|
244
253
|
|
|
@@ -258,7 +267,7 @@ export function DisplayFeatureRulesTable() {
|
|
|
258
267
|
</thead>
|
|
259
268
|
|
|
260
269
|
<tbody>
|
|
261
|
-
{
|
|
270
|
+
{rules.map((rule, index) => {
|
|
262
271
|
return (
|
|
263
272
|
<tr key={index} className={index % 2 === 0 ? undefined : "bg-gray-50"}>
|
|
264
273
|
<td className="py-4 pl-4 pr-3 text-sm text-gray-900">{rule.percentage}%</td>
|
|
@@ -295,7 +304,7 @@ export function DisplayFeatureRulesTable() {
|
|
|
295
304
|
|
|
296
305
|
export function DisplayFeatureRules() {
|
|
297
306
|
const { feature } = useOutletContext() as any;
|
|
298
|
-
const environmentKeys = Object.keys(feature.environments).sort();
|
|
307
|
+
const environmentKeys = feature.environments ? Object.keys(feature.environments).sort() : [];
|
|
299
308
|
|
|
300
309
|
const environmentTabs = environmentKeys.map((environmentKey) => {
|
|
301
310
|
return {
|
|
@@ -306,23 +315,29 @@ export function DisplayFeatureRules() {
|
|
|
306
315
|
|
|
307
316
|
return (
|
|
308
317
|
<>
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
318
|
+
{environmentKeys.length > 0 && (
|
|
319
|
+
<nav className="flex space-x-4" aria-label="Tabs">
|
|
320
|
+
{environmentTabs.map((tab) => (
|
|
321
|
+
<NavLink
|
|
322
|
+
key={tab.title}
|
|
323
|
+
to={tab.to}
|
|
324
|
+
className={({ isActive }) =>
|
|
325
|
+
[
|
|
326
|
+
isActive ? "bg-gray-200 text-gray-800" : "text-gray-600 hover:text-gray-800",
|
|
327
|
+
"rounded-md px-3 py-2 text-sm font-medium",
|
|
328
|
+
].join(" ")
|
|
329
|
+
}
|
|
330
|
+
>
|
|
331
|
+
{tab.title}
|
|
332
|
+
</NavLink>
|
|
333
|
+
))}
|
|
334
|
+
</nav>
|
|
335
|
+
)}
|
|
336
|
+
|
|
337
|
+
{/* no environments */}
|
|
338
|
+
{environmentKeys.length === 0 && <DisplayFeatureRulesTable />}
|
|
325
339
|
|
|
340
|
+
{/* with environments */}
|
|
326
341
|
<Outlet context={{ feature }} />
|
|
327
342
|
</>
|
|
328
343
|
);
|
package/src/utils/index.ts
CHANGED
|
@@ -95,22 +95,40 @@ export function isEnabledInEnvironment(feature: any, environment: string) {
|
|
|
95
95
|
return false;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
if (feature.environments) {
|
|
99
|
+
// with environments
|
|
100
|
+
if (!feature.environments[environment]) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
101
103
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
if (feature.environments[environment].expose === false) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
105
107
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
if (feature.environments[environment].rules.some((rule: any) => rule.percentage > 0)) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
// no environments
|
|
113
|
+
if (feature.rules.some((rule: any) => rule.percentage > 0)) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
108
116
|
}
|
|
109
117
|
|
|
110
118
|
return false;
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
export function isEnabledInAnyEnvironment(feature: any) {
|
|
122
|
+
// no environments
|
|
123
|
+
if (feature.rules) {
|
|
124
|
+
if (feature.rules.some((rule: any) => rule.percentage > 0)) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// with environments
|
|
114
132
|
const environments = Object.keys(feature.environments);
|
|
115
133
|
|
|
116
134
|
for (const environment of environments) {
|