Skip to content

Commit 979cf73

Browse files
authored
Merge branch 'main' into dependabot/npm_and_yarn/packages/openfeature-browser-provider/example/next-14.2.25
2 parents 9ed4782 + 7043dd3 commit 979cf73

82 files changed

Lines changed: 3647 additions & 2386 deletions

Some content is hidden

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

.github/workflows/publish.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ on:
44
push:
55
branches:
66
- main
7-
- v*
87

98
jobs:
109
release:

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
# Bucket
22

3-
Bucket is B2B feature flagging with a built-in feedback loop that lets you roll out features based on customer satisfaction.
4-
5-
[Learn more and get started](https://bucket.co/)
3+
Feature flags for SaaS that run on TypeScript. [Learn more and get started](https://bucket.co/)
64

75
## React SDK
86

97
Client side React SDK
108

119
[Read the docs](packages/react-sdk/README.md)
1210

11+
## Vue SDK (beta)
12+
13+
Client side Vue SDK
14+
15+
[Read the docs](packages/vue-sdk/README.md)
16+
1317
## Browser SDK
1418

1519
Browser SDK for use in non-React web applications

packages/browser-sdk/README.md

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ by down-stream clients, like the React SDK.
174174
Note that accessing `isEnabled` on the object returned by `getFeatures` does not automatically
175175
generate a `check` event, contrary to the `isEnabled` property on the object returned by `getFeature`.
176176

177-
## Remote config (beta)
177+
## Remote config
178178

179179
Remote config is a dynamic and flexible approach to configuring feature behavior outside of your app – without needing to re-deploy it.
180180

@@ -201,16 +201,6 @@ const features = bucketClient.getFeatures();
201201
Just as `isEnabled`, accessing `config` on the object returned by `getFeatures` does not automatically
202202
generate a `check` event, contrary to the `config` property on the object returned by `getFeature`.
203203

204-
## Tracking feature usage
205-
206-
The `track` function lets you send events to Bucket to denote feature usage.
207-
By default Bucket expects event names to align with the feature keys, but
208-
you can customize it as you wish.
209-
210-
```ts
211-
bucketClient.track("huddle", { voiceHuddle: true });
212-
```
213-
214204
## Updating user/company/other context
215205

216206
Attributes given for the user/company/other context in the BucketClient constructor can be updated for use in feature targeting evaluation with the `updateUser()`, `updateCompany()` and `updateOtherContext()` methods.
@@ -228,7 +218,43 @@ await bucketClient.updateUser({ voiceHuddleOptIn: (!isEnabled).toString() });
228218

229219
> [!NOTE] > `user`/`company` attributes are also stored remotely on the Bucket servers and will automatically be used to evaluate feature targeting if the page is refreshed.
230220
231-
## Qualitative feedback
221+
## Toolbar
222+
223+
The Bucket Toolbar is great for toggling features on/off for yourself to ensure that everything works both when a feature is on and when it's off.
224+
225+
<img width="352" alt="Toolbar screenshot" src="https://github.com/user-attachments/assets/c223df5a-4bd8-49a1-8b4a-ad7001357693" />
226+
227+
The toolbar will automatically appear on `localhost`. However, it can also be incredibly useful in production.
228+
You have full control over when it appears through the `toolbar` configuration option passed to the `BucketClient`.
229+
230+
You can pass a simple boolean to force the toolbar to appear/disappear:
231+
232+
```typescript
233+
const client = new BucketClient({
234+
// show the toolbar even in production if the user is an internal/admin user
235+
toolbar: user?.isInternal,
236+
...
237+
});
238+
```
239+
240+
You can also configure the position of the toolbar on the screen:
241+
242+
```typescript
243+
const client = new BucketClient({
244+
toolbar: {
245+
show: true;
246+
position: {
247+
placement: "bottom-left",
248+
offset: {x: "1rem", y: "1rem"}
249+
}
250+
}
251+
...
252+
})
253+
```
254+
255+
See [the reference](https://docs.bucket.co/supported-languages/browser-sdk/globals#toolbaroptions) for details.
256+
257+
## Qualitative feedback on beta features
232258

233259
Bucket can collect qualitative feedback from your users in the form of a [Customer Satisfaction Score](https://en.wikipedia.org/wiki/Customer_satisfaction) and a comment.
234260

@@ -248,8 +274,6 @@ You can find all the options to make changes to the default behavior in the [Buc
248274

249275
Bucket can assist you with collecting your user's feedback by offering a pre-built UI, allowing you to get started with minimal code and effort.
250276

251-
![image](https://github.com/bucketco/bucket-javascript-sdk/assets/34348/c387bac1-f2e2-4efd-9dda-5030d76f9532)
252-
253277
[Read the Bucket feedback UI documentation](./FEEDBACK.md)
254278

255279
### Bucket feedback SDK
@@ -270,42 +294,16 @@ If you are not using the Bucket Browser SDK, you can still submit feedback using
270294

271295
See details in [Feedback HTTP API](https://docs.bucket.co/reference/http-tracking-api#feedback)
272296

273-
## Toolbar
274-
275-
The Bucket Toolbar is great for toggling features on/off for yourself to ensure that everything works both when a feature is on and when it's off.
276-
277-
<img width="352" alt="Toolbar screenshot" src="https://github.com/user-attachments/assets/c223df5a-4bd8-49a1-8b4a-ad7001357693" />
278-
279-
The toolbar will automatically appear on `localhost`. However, it can also be incredibly useful in production.
280-
You have full control over when it appears through the `toolbar` configuration option passed to the `BucketClient`.
281-
282-
You can pass a simple boolean to force the toolbar to appear/disappear:
283-
284-
```typescript
285-
const client = new BucketClient({
286-
// show the toolbar even in production if the user is an internal/admin user
287-
toolbar: user?.isInternal,
288-
...
289-
});
290-
```
297+
## Tracking feature usage
291298

292-
You can also configure the position of the toolbar on the screen:
299+
The `track` function lets you send events to Bucket to denote feature usage.
300+
By default Bucket expects event names to align with the feature keys, but
301+
you can customize it as you wish.
293302

294-
```typescript
295-
const client = new BucketClient({
296-
toolbar: {
297-
show: true;
298-
position: {
299-
placement: "bottom-left",
300-
offset: {x: "1rem", y: "1rem"}
301-
}
302-
}
303-
...
304-
})
303+
```ts
304+
bucketClient.track("huddle", { voiceHuddle: true });
305305
```
306306

307-
See [the reference](https://docs.bucket.co/supported-languages/browser-sdk/globals#toolbaroptions) for details.
308-
309307
## Event listeners
310308

311309
Event listeners allow for capturing various events occurring in the `BucketClient`. This is useful to build integrations with other system or for various debugging purposes. There are 5 kinds of events:

packages/browser-sdk/eslint.config.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
const base = require("@bucketco/eslint-config");
2+
const preactConfig = require("eslint-config-preact");
3+
4+
const compatPlugin = require("eslint-plugin-compat");
5+
const reactPlugin = require("eslint-plugin-react");
6+
const reactHooksPlugin = require("eslint-plugin-react-hooks");
27

38
module.exports = [
49
...base,
510
{
611
// Preact projects
7-
files: ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"],
12+
files: ["**/*.tsx"],
13+
814
settings: {
915
react: {
1016
// We only care about marking h() as being a used variable.
@@ -13,10 +19,18 @@ module.exports = [
1319
version: "16.0",
1420
},
1521
},
22+
plugins: {
23+
compat: compatPlugin,
24+
react: reactPlugin,
25+
"react-hooks": reactHooksPlugin,
26+
},
1627
rules: {
28+
...preactConfig.rules,
1729
// Ignore React attributes that are not valid in Preact.
1830
// Alternatively, we could use the preact/compat alias or turn off the rule.
1931
"react/no-unknown-property": ["off"],
32+
"no-unused-vars": ["off"],
33+
"react/no-danger": ["off"],
2034
},
2135
},
2236
{ ignores: ["dist/", "example/"] },

packages/browser-sdk/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bucketco/browser-sdk",
3-
"version": "3.1.2",
3+
"version": "3.2.0",
44
"packageManager": "yarn@4.1.1",
55
"license": "MIT",
66
"repository": {
@@ -50,6 +50,7 @@
5050
"@vitest/coverage-v8": "^2.0.4",
5151
"c8": "~10.1.3",
5252
"eslint": "^9.21.0",
53+
"eslint-config-preact": "^1.5.0",
5354
"http-server": "^14.1.1",
5455
"jsdom": "^24.1.0",
5556
"msw": "^2.3.4",

packages/browser-sdk/src/client.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ export type FeatureRemoteConfig =
319319
export interface Feature {
320320
/**
321321
* Result of feature flag evaluation.
322+
* Note: Does not take local overrides into account.
322323
*/
323324
isEnabled: boolean;
324325

@@ -338,6 +339,17 @@ export interface Feature {
338339
requestFeedback: (
339340
options: Omit<RequestFeedbackData, "featureKey" | "featureId">,
340341
) => void;
342+
343+
/**
344+
* The current override status of isEnabled for the feature.
345+
*/
346+
isEnabledOverride: boolean | null;
347+
348+
/**
349+
* Set the override status for isEnabled for the feature.
350+
* Set to `null` to remove the override.
351+
*/
352+
setIsEnabledOverride(isEnabled: boolean | null): void;
341353
}
342354

343355
function shouldShowToolbar(opts: InitOptions) {
@@ -778,23 +790,13 @@ export class BucketClient {
778790
...options,
779791
});
780792
},
793+
isEnabledOverride: this.featuresClient.getFeatureOverride(key),
794+
setIsEnabledOverride(isEnabled: boolean | null) {
795+
self.featuresClient.setFeatureOverride(key, isEnabled);
796+
},
781797
};
782798
}
783799

784-
/**
785-
* @internal
786-
*/
787-
setFeatureOverride(key: string, isEnabled: boolean | null) {
788-
this.featuresClient.setFeatureOverride(key, isEnabled);
789-
}
790-
791-
/**
792-
* @internal
793-
*/
794-
getFeatureOverride(key: string): boolean | null {
795-
return this.featuresClient.getFeatureOverride(key);
796-
}
797-
798800
private sendCheckEvent(checkEvent: CheckEvent) {
799801
return this.featuresClient.sendCheckEvent(checkEvent, () => {
800802
this.hooks.trigger(

packages/browser-sdk/src/feedback/ui/FeedbackForm.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ export const FeedbackForm: FunctionComponent<FeedbackFormProps> = ({
9090
if (headerRef.current === null) return;
9191
if (expandedContentRef.current === null) return;
9292

93-
containerRef.current.style.maxHeight =
94-
headerRef.current.clientHeight + "px";
93+
containerRef.current.style.maxHeight = `${headerRef.current.clientHeight}px`;
9594

9695
expandedContentRef.current.style.position = "absolute";
9796
expandedContentRef.current.style.opacity = "0";
@@ -103,11 +102,11 @@ export const FeedbackForm: FunctionComponent<FeedbackFormProps> = ({
103102
if (headerRef.current === null) return;
104103
if (expandedContentRef.current === null) return;
105104

106-
containerRef.current.style.maxHeight =
105+
containerRef.current.style.maxHeight = `${
107106
headerRef.current.clientHeight + // Header height
108107
expandedContentRef.current.clientHeight + // Comment + Button Height
109-
10 + // Gap height
110-
"px";
108+
10 // Gap height
109+
}px`;
111110

112111
expandedContentRef.current.style.position = "relative";
113112
expandedContentRef.current.style.opacity = "1";
@@ -121,8 +120,7 @@ export const FeedbackForm: FunctionComponent<FeedbackFormProps> = ({
121120

122121
formRef.current.style.opacity = "0";
123122
formRef.current.style.pointerEvents = "none";
124-
containerRef.current.style.maxHeight =
125-
submittedRef.current.clientHeight + "px";
123+
containerRef.current.style.maxHeight = `${submittedRef.current.clientHeight}px`;
126124

127125
// Fade in "submitted" step once container has resized
128126
setTimeout(() => {

packages/browser-sdk/src/feedback/ui/StarRating.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const scores = [
5252
},
5353
] as const;
5454

55-
type Score = (typeof scores)[number];
55+
type ScoreNumber = (typeof scores)[number];
5656

5757
export type StarRatingProps = {
5858
name: string;
@@ -118,7 +118,7 @@ const Score = ({
118118
isSelected: boolean;
119119
name: string;
120120
onChange?: h.JSX.GenericEventHandler<HTMLInputElement>;
121-
score: Score;
121+
score: ScoreNumber;
122122
t: FeedbackTranslations;
123123
}) => {
124124
const arrowRef = useRef<HTMLDivElement>(null);

packages/browser-sdk/src/toolbar/Features.css

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,7 @@
9797
}
9898

9999
.reset {
100-
color: var(--brand300);
101-
100+
color: var(--gray500);
102101
text-decoration: none;
103102

104103
&:hover,

0 commit comments

Comments
 (0)