@featurevisor/site 1.31.0 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@featurevisor/site",
3
- "version": "1.31.0",
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.31.0"
62
+ "@featurevisor/types": "1.32.0"
63
63
  },
64
- "gitHead": "fddbfd83a41ff252d0f67410a9208665b51d412f"
64
+ "gitHead": "c360fac0c91b586847633c2d41cf5e4d6922a9b8"
65
65
  }
@@ -50,7 +50,7 @@ export function App() {
50
50
  }, []);
51
51
 
52
52
  const environmentKeys = fetchedSearchIndex
53
- ? Object.keys((fetchedSearchIndex as SearchIndex).entities.features[0].environments).sort()
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 index element={<Navigate to={environmentKeys[0]} replace />} />
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 index element={<Navigate to={environmentKeys[0]} replace />} />
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
- if (
114
- !environmentKey ||
115
- !feature.environments[environmentKey] ||
116
- !feature.environments[environmentKey].force
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
- {feature.environments[environmentKey].force.map((force, index) => {
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
- <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>
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
- if (!environmentKey || !feature.environments[environmentKey]) {
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
- {feature.environments[environmentKey].expose === false && (
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(feature.environments[environmentKey].expose) && (
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: {feature.environments[environmentKey].expose.join(", ")}.
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
- {feature.environments[environmentKey].rules.map((rule, index) => {
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
- <nav className="flex space-x-4" aria-label="Tabs">
310
- {environmentTabs.map((tab) => (
311
- <NavLink
312
- key={tab.title}
313
- to={tab.to}
314
- className={({ isActive }) =>
315
- [
316
- isActive ? "bg-gray-200 text-gray-800" : "text-gray-600 hover:text-gray-800",
317
- "rounded-md px-3 py-2 text-sm font-medium",
318
- ].join(" ")
319
- }
320
- >
321
- {tab.title}
322
- </NavLink>
323
- ))}
324
- </nav>
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
  );
@@ -95,22 +95,40 @@ export function isEnabledInEnvironment(feature: any, environment: string) {
95
95
  return false;
96
96
  }
97
97
 
98
- if (!feature.environments[environment]) {
99
- return false;
100
- }
98
+ if (feature.environments) {
99
+ // with environments
100
+ if (!feature.environments[environment]) {
101
+ return false;
102
+ }
101
103
 
102
- if (feature.environments[environment].expose === false) {
103
- return false;
104
- }
104
+ if (feature.environments[environment].expose === false) {
105
+ return false;
106
+ }
105
107
 
106
- if (feature.environments[environment].rules.some((rule: any) => rule.percentage > 0)) {
107
- return true;
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) {