@featurevisor/site 1.35.3 → 2.0.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/README.md +1 -7
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/lib/contexts/SearchIndexContext.d.ts +1 -1
- package/lib/hooks/useSearchIndex.d.ts +1 -1
- package/lib/utils/index.d.ts +1 -2
- package/mock/search-index.json +632 -291
- package/package.json +3 -3
- package/src/components/App.tsx +1 -1
- package/src/components/ListAttributes.tsx +0 -5
- package/src/components/ShowAttribute.tsx +0 -6
- package/src/components/ShowFeature.tsx +47 -38
- package/src/contexts/SearchIndexContext.tsx +1 -1
- package/src/hooks/useSearchIndex.ts +1 -1
- package/src/utils/index.ts +9 -29
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@featurevisor/site",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.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": "
|
|
62
|
+
"@featurevisor/types": "2.0.0"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "9817e05a07735294c750ee921991509b67015afd"
|
|
65
65
|
}
|
package/src/components/App.tsx
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
} from "./ShowFeature";
|
|
37
37
|
|
|
38
38
|
import { SearchIndexContext } from "../contexts/SearchIndexContext";
|
|
39
|
-
import { SearchIndex } from "@featurevisor/types";
|
|
39
|
+
import type { SearchIndex } from "@featurevisor/types";
|
|
40
40
|
|
|
41
41
|
export function App() {
|
|
42
42
|
const [fetchedSearchIndex, setSearchIndex] = React.useState(undefined);
|
|
@@ -33,11 +33,6 @@ export function ListAttributes() {
|
|
|
33
33
|
<div className="flex items-center justify-between">
|
|
34
34
|
<p className="text-md relative font-bold text-slate-600">
|
|
35
35
|
{attribute.key}{" "}
|
|
36
|
-
{attribute.capture && (
|
|
37
|
-
<span className="ml-1 rounded-full bg-green-100 px-2 py-1 text-xs font-medium text-green-800">
|
|
38
|
-
capture
|
|
39
|
-
</span>
|
|
40
|
-
)}
|
|
41
36
|
{attribute.archived && (
|
|
42
37
|
<span className="ml-1 rounded-full bg-red-100 px-2 py-1 text-xs font-medium text-red-800">
|
|
43
38
|
archived
|
|
@@ -29,12 +29,6 @@ export function DisplayAttributeOverview() {
|
|
|
29
29
|
<dt className="text-sm font-medium text-gray-500">Type</dt>
|
|
30
30
|
<dd className="mt-1 text-sm text-gray-900">{attribute.type}</dd>
|
|
31
31
|
</div>
|
|
32
|
-
<div>
|
|
33
|
-
<dt className="text-sm font-medium text-gray-500">Capture</dt>
|
|
34
|
-
<dd className="mt-1 text-sm text-gray-900">
|
|
35
|
-
{attribute.capture === true ? <span>Yes</span> : <span>No</span>}
|
|
36
|
-
</dd>
|
|
37
|
-
</div>
|
|
38
32
|
<div className="col-span-2">
|
|
39
33
|
<dt className="text-sm font-medium text-gray-500">Description</dt>
|
|
40
34
|
<dd className="mt-1 text-sm text-gray-900">
|
|
@@ -111,7 +111,9 @@ export function DisplayFeatureForceTable() {
|
|
|
111
111
|
const { environmentKey } = useParams();
|
|
112
112
|
|
|
113
113
|
const envKey = environmentKey as string;
|
|
114
|
-
|
|
114
|
+
|
|
115
|
+
const force =
|
|
116
|
+
feature.force && !Array.isArray(feature.rules) ? feature.force[envKey] : feature.force;
|
|
115
117
|
|
|
116
118
|
if (!force || force.length === 0) {
|
|
117
119
|
return <p>n/a</p>;
|
|
@@ -184,7 +186,8 @@ export function DisplayFeatureForceTable() {
|
|
|
184
186
|
|
|
185
187
|
export function DisplayFeatureForce() {
|
|
186
188
|
const { feature } = useOutletContext() as any;
|
|
187
|
-
const environmentKeys =
|
|
189
|
+
const environmentKeys =
|
|
190
|
+
feature.force && !Array.isArray(feature.force) ? Object.keys(feature.force).sort() : [];
|
|
188
191
|
|
|
189
192
|
const environmentTabs = environmentKeys.map((environmentKey) => {
|
|
190
193
|
return {
|
|
@@ -228,8 +231,11 @@ export function DisplayFeatureRulesTable() {
|
|
|
228
231
|
const { environmentKey } = useParams();
|
|
229
232
|
|
|
230
233
|
const envKey = environmentKey as string;
|
|
231
|
-
const rules = feature.
|
|
232
|
-
const expose =
|
|
234
|
+
const rules = !Array.isArray(feature.rules) ? feature.rules[envKey] : feature.rules;
|
|
235
|
+
const expose =
|
|
236
|
+
typeof feature.expose !== "undefined" && !Array.isArray(feature.rules)
|
|
237
|
+
? feature.expose[envKey]
|
|
238
|
+
: feature.expose;
|
|
233
239
|
|
|
234
240
|
if (!rules || rules.length === 0) {
|
|
235
241
|
return <p>n/a</p>;
|
|
@@ -304,7 +310,7 @@ export function DisplayFeatureRulesTable() {
|
|
|
304
310
|
|
|
305
311
|
export function DisplayFeatureRules() {
|
|
306
312
|
const { feature } = useOutletContext() as any;
|
|
307
|
-
const environmentKeys = feature.
|
|
313
|
+
const environmentKeys = feature.rules ? Object.keys(feature.rules).sort() : [];
|
|
308
314
|
|
|
309
315
|
const environmentTabs = environmentKeys.map((environmentKey) => {
|
|
310
316
|
return {
|
|
@@ -390,15 +396,17 @@ export function DisplayFeatureVariations() {
|
|
|
390
396
|
<th className="py-4 pl-4 pr-3 text-sm font-medium text-gray-700">
|
|
391
397
|
{variation.variables && (
|
|
392
398
|
<ul className="list-inside list-disc text-left">
|
|
393
|
-
{variation.variables.map((
|
|
399
|
+
{Object.keys(variation.variables).map((variableKey) => {
|
|
400
|
+
const variableValue = variation.variables[variableKey];
|
|
401
|
+
|
|
394
402
|
return (
|
|
395
|
-
<li key={
|
|
396
|
-
<span className="font-semibold">{
|
|
397
|
-
{typeof
|
|
398
|
-
|
|
403
|
+
<li key={variableKey}>
|
|
404
|
+
<span className="font-semibold">{variableKey}</span>:{" "}
|
|
405
|
+
{typeof variableValue === "string" ? (
|
|
406
|
+
variableValue
|
|
399
407
|
) : (
|
|
400
408
|
<pre className="rounded bg-gray-100 px-2 py-1 text-red-400">
|
|
401
|
-
<code>{JSON.stringify(
|
|
409
|
+
<code>{JSON.stringify(variableValue, null, 2)}</code>
|
|
402
410
|
</pre>
|
|
403
411
|
)}
|
|
404
412
|
</li>
|
|
@@ -422,7 +430,7 @@ export function DisplayFeatureVariations() {
|
|
|
422
430
|
export function DisplayFeatureVariablesSchema() {
|
|
423
431
|
const { feature } = useOutletContext() as any;
|
|
424
432
|
|
|
425
|
-
if (!feature.variablesSchema
|
|
433
|
+
if (!feature.variablesSchema) {
|
|
426
434
|
return <p>n/a</p>;
|
|
427
435
|
}
|
|
428
436
|
|
|
@@ -440,32 +448,33 @@ export function DisplayFeatureVariablesSchema() {
|
|
|
440
448
|
</thead>
|
|
441
449
|
|
|
442
450
|
<tbody>
|
|
443
|
-
{feature.variablesSchema
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
variableSchema.
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
<
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
451
|
+
{feature.variablesSchema &&
|
|
452
|
+
Object.keys(feature.variablesSchema).map((variableKey, index) => {
|
|
453
|
+
const variableSchema = feature.variablesSchema[variableKey];
|
|
454
|
+
|
|
455
|
+
return (
|
|
456
|
+
<tr key={variableSchema.key} className={index % 2 === 0 ? undefined : "bg-gray-50"}>
|
|
457
|
+
<td className="py-4 pl-4 pr-3 text-sm font-medium text-gray-700">{variableKey}</td>
|
|
458
|
+
<td className="py-4 pl-4 pr-3 text-sm font-medium text-gray-700">
|
|
459
|
+
{variableSchema.type}
|
|
460
|
+
</td>
|
|
461
|
+
<td className="py-4 pl-4 pr-3 text-sm font-medium text-gray-700">
|
|
462
|
+
{variableSchema.type === "string" ? (
|
|
463
|
+
variableSchema.defaultValue
|
|
464
|
+
) : (
|
|
465
|
+
<pre>
|
|
466
|
+
<code className="rounded bg-gray-100 px-2 py-1 text-red-400">
|
|
467
|
+
{JSON.stringify(variableSchema.defaultValue, null, 2)}
|
|
468
|
+
</code>
|
|
469
|
+
</pre>
|
|
470
|
+
)}
|
|
471
|
+
</td>
|
|
472
|
+
<td className="py-4 pl-4 pr-3 text-sm font-medium text-gray-700">
|
|
473
|
+
{variableSchema.description || <span>n/a</span>}
|
|
474
|
+
</td>
|
|
475
|
+
</tr>
|
|
476
|
+
);
|
|
477
|
+
})}
|
|
469
478
|
</tbody>
|
|
470
479
|
</table>
|
|
471
480
|
);
|
package/src/utils/index.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { SearchIndex } from "@featurevisor/types";
|
|
1
|
+
import type { SearchIndex } from "@featurevisor/types";
|
|
2
2
|
|
|
3
3
|
export interface Query {
|
|
4
4
|
keyword: string;
|
|
5
5
|
tags: string[];
|
|
6
6
|
environments: string[];
|
|
7
7
|
archived?: boolean;
|
|
8
|
-
capture?: boolean;
|
|
9
8
|
hasVariations?: boolean;
|
|
10
9
|
hasVariables?: boolean;
|
|
11
10
|
variableKeys?: string[];
|
|
@@ -18,7 +17,6 @@ export function parseSearchQuery(queryString: string) {
|
|
|
18
17
|
tags: [],
|
|
19
18
|
environments: [],
|
|
20
19
|
archived: undefined,
|
|
21
|
-
capture: undefined,
|
|
22
20
|
};
|
|
23
21
|
|
|
24
22
|
const parts = queryString.split(" ");
|
|
@@ -44,14 +42,6 @@ export function parseSearchQuery(queryString: string) {
|
|
|
44
42
|
} else if (archived === "false") {
|
|
45
43
|
query.archived = false;
|
|
46
44
|
}
|
|
47
|
-
} else if (part.startsWith("capture:")) {
|
|
48
|
-
const capture = part.replace("capture:", "");
|
|
49
|
-
|
|
50
|
-
if (capture === "true") {
|
|
51
|
-
query.capture = true;
|
|
52
|
-
} else if (capture === "false") {
|
|
53
|
-
query.capture = false;
|
|
54
|
-
}
|
|
55
45
|
} else if (part.startsWith("variable:")) {
|
|
56
46
|
const variableKey = part.replace("variable:", "");
|
|
57
47
|
|
|
@@ -95,20 +85,20 @@ export function isEnabledInEnvironment(feature: any, environment: string) {
|
|
|
95
85
|
return false;
|
|
96
86
|
}
|
|
97
87
|
|
|
98
|
-
if (feature.
|
|
88
|
+
if (!Array.isArray(feature.rules)) {
|
|
99
89
|
// with environments
|
|
100
|
-
if (!feature.
|
|
90
|
+
if (!feature.rules[environment]) {
|
|
101
91
|
return false;
|
|
102
92
|
}
|
|
103
93
|
|
|
104
|
-
if (feature.
|
|
94
|
+
if (feature.rules[environment].expose === false) {
|
|
105
95
|
return false;
|
|
106
96
|
}
|
|
107
97
|
|
|
108
|
-
if (feature.
|
|
98
|
+
if (feature.rules[environment].some((rule: any) => rule.percentage > 0)) {
|
|
109
99
|
return true;
|
|
110
100
|
}
|
|
111
|
-
} else {
|
|
101
|
+
} else if (feature.rules) {
|
|
112
102
|
// no environments
|
|
113
103
|
if (feature.rules.some((rule: any) => rule.percentage > 0)) {
|
|
114
104
|
return true;
|
|
@@ -120,7 +110,7 @@ export function isEnabledInEnvironment(feature: any, environment: string) {
|
|
|
120
110
|
|
|
121
111
|
export function isEnabledInAnyEnvironment(feature: any) {
|
|
122
112
|
// no environments
|
|
123
|
-
if (feature.rules) {
|
|
113
|
+
if (Array.isArray(feature.rules)) {
|
|
124
114
|
if (feature.rules.some((rule: any) => rule.percentage > 0)) {
|
|
125
115
|
return true;
|
|
126
116
|
}
|
|
@@ -129,7 +119,7 @@ export function isEnabledInAnyEnvironment(feature: any) {
|
|
|
129
119
|
}
|
|
130
120
|
|
|
131
121
|
// with environments
|
|
132
|
-
const environments = Object.keys(feature.
|
|
122
|
+
const environments = Object.keys(feature.rules);
|
|
133
123
|
|
|
134
124
|
for (const environment of environments) {
|
|
135
125
|
const isEnabled = isEnabledInEnvironment(feature, environment);
|
|
@@ -206,7 +196,7 @@ export function getFeaturesByQuery(query: Query, data: SearchIndex) {
|
|
|
206
196
|
if (!feature.variablesSchema) {
|
|
207
197
|
matched = false;
|
|
208
198
|
} else {
|
|
209
|
-
const keysFromFeature = feature.variablesSchema
|
|
199
|
+
const keysFromFeature = Object.keys(feature.variablesSchema);
|
|
210
200
|
|
|
211
201
|
if (query.variableKeys.some((k) => keysFromFeature.indexOf(k) === -1)) {
|
|
212
202
|
matched = false;
|
|
@@ -253,16 +243,6 @@ export function getAttributesByQuery(query: Query, data: SearchIndex) {
|
|
|
253
243
|
}
|
|
254
244
|
}
|
|
255
245
|
|
|
256
|
-
if (typeof query.capture === "boolean") {
|
|
257
|
-
if (query.capture && a.capture !== query.capture) {
|
|
258
|
-
matched = false;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (!query.capture && a.capture === true) {
|
|
262
|
-
matched = false;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
246
|
return matched;
|
|
267
247
|
})
|
|
268
248
|
.sort((a, b) => a.key.localeCompare(b.key));
|