Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions clientlibs/js/ff-playground-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.

# Compiled output
/dist
/tmp
/out-tsc
/bazel-out

# Node
/node_modules
npm-debug.log
yarn-error.log

# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*

# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
__screenshots__/

# System files
.DS_Store
Thumbs.db
61 changes: 61 additions & 0 deletions clientlibs/js/ff-playground-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Feature Flag Playground

A minimal Angular app for trying out the recipes in
[`../docs/feature-flags-guide.md`](../docs/feature-flags-guide.md) against a real, running UpGrade backend.
Comment thread
danoswaltCL marked this conversation as resolved.

There are only two source files:

- `src/app/feature-flag-playground.service.ts` — **the file to edit.** All `upgrade_client_lib`
usage lives here. `login()` currently uses the recommended ephemeral-mode recipe for the square,
and an ad-hoc `groupsets` override for the circles. Alternate recipes (stored mode, merged mode)
are included as commented-out blocks — swap them in to see how behavior changes.
- `src/app/app.ts` — a single barebones component: a login form (user id + repeatable
group-type/values rows) and, once logged in, the two flag displays described below.

## Prerequisites

1. The UpGrade backend running locally at `http://localhost:3030` (`docker-compose up` from the
repo root, or however you normally run it). CORS already allows any `localhost` port, so the
Angular dev server's port doesn't matter.
2. Two feature flags created via the admin UI, both under context **`upgrade-internal`**:
- `SQUARE_COLOR_FLAG_FOR_USER` — drives the square. Include/exclude it by whatever
class/school/district/instructor groups you plan to log in with.
- `SCHOOL_CIRCLE_FLAG` — drives the per-schoolId circles. Since each circle is checked as its
own ephemeral groupset containing only that one schoolId, scope this flag's inclusion by
`schoolId` if you want some circles green and others red.

Until these exist, everything will just show as "off" (red) — that's expected, not a bug.

## Running it

```bash
yarn install # first time only; also re-run this after rebuilding the SDK (see below)
yarn start # ng serve, on http://localhost:4300 (4200 is reserved for the UpGrade admin UI)
```

## Using it

1. Enter a user id, or leave it blank to have one generated.
2. Add zero or more group rows — pick a type (`classId` / `schoolId` / `districtId` /
`instructorId`) and type comma-separated values.
3. Click **Log in**. This does not call `init()` — it configures an ephemeral-mode
`UpgradeClient` with exactly the groups you entered, and fetches both flags.
4. The square is colored by `SQUARE_COLOR_FLAG_FOR_USER` for the whole set of groups you entered.
The circles row shows one circle per `schoolId` you entered, each independently colored by
`SCHOOL_CIRCLE_FLAG` for that one schoolId. If you didn't enter any schoolIds, it says so
instead of showing an empty row.
5. **Log out** and repeat with different groups/ids to compare.

## Picking up SDK changes

This app depends on `upgrade_client_lib` via a local `file:` dependency pointing at
`../packages/full-browser` (which `npm run build` in `clientlibs/js` populates from `../dist/browser`).
After changing the client library source:

```bash
cd ../ && npm run build # rebuilds clientlibs/js, including packages/full-browser
cd ff-playground-app && yarn install --offline # re-copies the local dependency
```

`yarn start` needs to be restarted afterward to pick up the change (Angular's dev server does not
watch outside `src/`).
109 changes: 109 additions & 0 deletions clientlibs/js/ff-playground-app/angular.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"packageManager": "yarn"
},
"newProjectRoot": "projects",
"projects": {
"ff-playground-app": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"inlineTemplate": true,
"inlineStyle": true,
"skipTests": true
},
"@schematics/angular:class": {
"skipTests": true
},
"@schematics/angular:directive": {
"skipTests": true
},
"@schematics/angular:guard": {
"skipTests": true
},
"@schematics/angular:interceptor": {
"skipTests": true
},
"@schematics/angular:pipe": {
"skipTests": true
},
"@schematics/angular:resolver": {
"skipTests": true
},
"@schematics/angular:service": {
"skipTests": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular/build:application",
"options": {
"browser": "src/main.ts",
"polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": [
"src/styles.css"
],
"allowedCommonJsDependencies": [
"upgrade_client_lib"
]
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "750kB",
"maximumError": "1.5MB"
},
{
"type": "anyComponentStyle",
"maximumWarning": "4kB",
"maximumError": "8kB"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular/build:dev-server",
"options": {
"port": 4300
},
"configurations": {
"production": {
"buildTarget": "ff-playground-app:build:production"
},
"development": {
"buildTarget": "ff-playground-app:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular/build:extract-i18n"
}
}
}
}
}
39 changes: 39 additions & 0 deletions clientlibs/js/ff-playground-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "ff-playground-app",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"prettier": {
"printWidth": 100,
"singleQuote": true,
"overrides": [
{
"files": "*.html",
"options": {
"parser": "angular"
}
}
]
},
"private": true,
"dependencies": {
"@angular/common": "^20.3.0",
"@angular/compiler": "^20.3.0",
"@angular/core": "^20.3.0",
"@angular/platform-browser": "^20.3.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"upgrade_client_lib": "file:../packages/full-browser",
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular/build": "^20.3.32",
"@angular/cli": "^20.3.32",
"@angular/compiler-cli": "^20.3.0",
"typescript": "~5.9.2"
}
}
Binary file not shown.
9 changes: 9 additions & 0 deletions clientlibs/js/ff-playground-app/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZoneChangeDetection } from '@angular/core';

export const appConfig: ApplicationConfig = {
providers: [
provideBrowserGlobalErrorListeners(),
provideZoneChangeDetection({ eventCoalescing: true }),

]
};
Loading