Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f3eca4f
change task creation polling to once 15 secs
chandan-m May 8, 2026
b5d72aa
storybook demo - wip - 2
chandan-m May 8, 2026
b54e4fe
storybook demo - wip - 2
chandan-m May 8, 2026
21a4e8c
fix - end of review flow
chandan-m May 8, 2026
1d4f3e9
fix - type errors
chandan-m May 8, 2026
a2a5038
change stories
chandan-m May 8, 2026
69c2a2c
storybook demo - wip - 3
chandan-m May 8, 2026
40e566c
storybook demo - wip - 3
chandan-m May 8, 2026
7753f3c
default light mode
chandan-m May 8, 2026
83c18e7
fix light mode
chandan-m May 8, 2026
bffaf8b
storybook deployment
chandan-m May 8, 2026
b2a4ace
storybook deployment - gh actions cicd
chandan-m May 8, 2026
5a66410
Remove unimplemented Annotate Dataset task pages
chandan-m May 13, 2026
52ca9d8
Cleanup
chandan-m May 13, 2026
a00ca67
Cleanup
chandan-m May 13, 2026
e1ff5b0
Enter details directly on Create task page
chandan-m May 13, 2026
0f2cbc4
New Landing Page with Intuitive examples
chandan-m May 13, 2026
48ff19f
Demo wip
chandan-m May 13, 2026
32a7790
Demo wip - Create task page
chandan-m May 13, 2026
0f12f00
Demo wip - Ai Annotation page
chandan-m May 13, 2026
caad7ba
Demo wip - Ai Annotation page - 1
chandan-m May 13, 2026
dd2e77f
Demo wip - Ai Annotation page - 2
chandan-m May 13, 2026
ce07148
Demo wip - Ai Annotation page - 3
chandan-m May 13, 2026
f69a7b4
Completed Demo page and Landing page changes
chandan-m May 13, 2026
1ab3622
Demo build complete
chandan-m May 13, 2026
0b7a1c6
Remove storybook
chandan-m May 13, 2026
5bb7103
Update README.md
chandan-m May 13, 2026
39fc43c
Github CI for demo page deployment to GitHub Pages
chandan-m May 13, 2026
d98d97c
fix demo page in live site
chandan-m May 13, 2026
26ce696
Pilot banner
chandan-m May 13, 2026
b5fe792
Update README.md
chandan-m May 13, 2026
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
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
APP_MODE=DEFAULT
# Frontend environment variables belong in frontend/.env — see frontend/.env.example
# Backend environment variables belong in backend/.env
52 changes: 52 additions & 0 deletions .github/workflows/deploy-demo-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Deploy Demo to GitHub Pages

# TODO: change 'static-ui' to 'main' after this branch is merged
on:
push:
branches:
- static-ui
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
cancel-in-progress: true

jobs:
build-and-deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
run: npm ci
working-directory: frontend

- name: Build demo
run: npm run build:demo
working-directory: frontend

- name: Setup Pages
uses: actions/configure-pages@v5

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: frontend/dist-demo

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ backend/

# Runtime Modes

Create a repo-level `.env` file (you can copy from `.env.example`) and set:
## Backend sampling mode

Create `backend/.env` (copy from `backend/.env.example`) and set:

```bash
APP_MODE=UI_DEV
Expand All @@ -24,4 +26,14 @@ When `APP_MODE=UI_DEV`:
- Representative sampling is skipped (the uploaded unlabeled dataset is used directly).
- Coverage sampling is replaced with fast random sampling.

Use `APP_MODE=DEFAULT` (or unset it) for full representative + coverage sampling.
Use `APP_MODE=DEFAULT` (or omit it) for full representative + coverage sampling.

## Pilot mode

To show a pilot banner across the live app (landing page, login, and all authenticated pages), create `frontend/.env` and set:

```bash
VITE_APP_MODE=pilot
```

The banner is not shown in the demo site regardless of this setting. Remove the variable or leave it blank to disable the banner.
4 changes: 2 additions & 2 deletions backend/src/routes/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ router.post(
uploadBundle.fields([
{ name: "d_val", maxCount: 1 },
{ name: "d_all", maxCount: 1 },
{ name: "task_json", maxCount: 1 },
{ name: "labels_json", maxCount: 1 },
{ name: "task_json", maxCount: 1 },
]),
uploadTaskBundle,
);
Expand All @@ -41,8 +41,8 @@ router.post(
uploadBundle.fields([
{ name: "d_val", maxCount: 1 },
{ name: "d_all", maxCount: 1 },
{ name: "task_json", maxCount: 1 },
{ name: "labels_json", maxCount: 1 },
{ name: "task_json", maxCount: 1 },
]),
uploadTaskBundle,
);
Expand Down
44 changes: 37 additions & 7 deletions backend/src/services/tasks.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -762,36 +762,66 @@ export async function uploadTaskBundle(req: AuthRequest, res: Response) {
const dAllFile = files?.d_all?.[0];
const taskJsonFile = files?.task_json?.[0];
const labelsJsonFile = files?.labels_json?.[0];
const taskNameField = req.body.task_name as string | undefined;
const taskDescriptionField = req.body.task_description as string | undefined;
const taskTypeField = req.body.task_type as string | undefined;
const textColumn = req.body.text_column as string | undefined;
const labelColumn = req.body.label_column as string | undefined;
const modelName = req.body.model_name as string | undefined;

if (
!dValFile ||
!dAllFile ||
!taskJsonFile ||
!labelsJsonFile ||
!labelColumn
) {
console.error("[uploadTaskBundle] Missing files:", {
d_val: !!dValFile,
d_all: !!dAllFile,
task_json: !!taskJsonFile,
task_name: !!taskNameField,
task_description: !!taskDescriptionField,
labels_json: !!labelsJsonFile,
labelColumn: !!labelColumn,
});
return res.status(400).json({
success: false,
message:
"Missing files. Expected d_val, d_all, task_json, labels_json and label column",
"Missing fields. Expected d_val, d_all, labels_json, label column, and either task_json or task_name + task_description",
});
}

// Parse Task JSON
console.log("[uploadTaskBundle] Parsing task_json...");
const taskJsonRaw = taskJsonFile.buffer.toString("utf-8");
const taskInfo = parseTaskJson(taskJsonFile.buffer);
console.log("[uploadTaskBundle] Task Info parsed:", taskInfo.name);
let taskJsonRaw = "";
let taskInfo: {
name: string;
description: string;
type: Task["type"];
};
if (taskJsonFile) {
console.log("[uploadTaskBundle] Parsing task_json...");
taskJsonRaw = taskJsonFile.buffer.toString("utf-8");
taskInfo = parseTaskJson(taskJsonFile.buffer);
console.log("[uploadTaskBundle] Task Info parsed from file:", taskInfo.name);
} else {
const name = String(taskNameField ?? "").trim();
const description = String(taskDescriptionField ?? "").trim();
if (!name || !description) {
return res.status(400).json({
success: false,
message:
"Task name and description are required when task_json is not provided.",
});
}
const type: Task["type"] =
taskTypeField === "Single-class" ? "Single-class" : "Multiclass";
taskInfo = { name, description, type };
taskJsonRaw = JSON.stringify(
{ taskname: name, description, type },
null,
2,
);
console.log("[uploadTaskBundle] Task Info parsed from form fields:", taskInfo.name);
}

// Parse Labels JSON
console.log("[uploadTaskBundle] Parsing labels_json...");
Expand Down
3 changes: 3 additions & 0 deletions frontend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Set to "pilot" to show the Pilot Mode banner in the live app.
# Leave unset (or any other value) for normal deployment. No banner in demo mode regardless.
VITE_APP_MODE=
4 changes: 4 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ dist-ssr
*.njsproj
*.sln
*.sw?

*storybook.log
storybook-static
dist-demo
134 changes: 74 additions & 60 deletions frontend/README.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,87 @@
# React + TypeScript + Vite
# Annotation Assistant — Frontend

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
React + TypeScript + Vite frontend for Annotation Assistant.

Currently, two official plugins are available:
## Development

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
```bash
npm install
npm run dev # http://localhost:5173
```

The dev server includes a live demo at `http://localhost:5173/demo`.

## Demo — build and run locally

The demo is a self-contained static build with mocked API responses. No backend required.

**Build:**

```bash
npm install
npm run build:demo
```

Output is written to `dist-demo/`.

**Run:**

```bash
cd dist-demo
npx serve .
```

## React Compiler
Open `http://localhost:3000` in your browser.

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
**Share as a zip:**

## Expanding the ESLint configuration
```bash
npm run build:demo
zip -r annotation-demo.zip dist-demo/
```

Recipients unzip and run `npx serve .` inside the folder.

## GitHub Pages deployment (repo owner action required)

The workflow at `.github/workflows/deploy-demo-pages.yml` builds and deploys the demo to GitHub Pages automatically on every push to `main`. (Need to change the branch github workflow after merge, currently points to `static-ui` branch)

Because this is a private repository, GitHub Pages must be explicitly enabled and made public by a **repo owner or admin**. This cannot be done by collaborators.

### One-time setup steps

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
1. **Enable GitHub Actions write access**
- Go to **Settings → Actions → General**
- Under *Workflow permissions*, select **Read and write permissions**
- Save

```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
2. **Enable GitHub Pages**
- Go to **Settings → Pages**
- Under *Source*, select **GitHub Actions** (not a branch)
- Save

// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
3. **Make the Pages site public** *(private repo requirement)*
- Still on **Settings → Pages**
- Check the visibility — GitHub may require a paid plan (GitHub Team or Enterprise) to have a public Pages site from a private repo
- If available, set visibility to **Public**
- If not available on your plan, consider mirroring the `dist-demo/` output to a separate public repo and deploying from there

// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
4. **Change the workflow branch trigger to `main`**
- In `.github/workflows/deploy-demo-pages.yml`, change `static-ui` to `main` after merging this branch
- There is a `# TODO` comment marking the line

### After setup

Every push to `main` triggers a build and deploys to:
```
https://<org-or-user>.github.io/<repo-name>/
```

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
You can also trigger a deployment manually from the **Actions** tab → **Deploy Demo to GitHub Pages** → **Run workflow**.

## Production build

```bash
npm run build # output → dist/
npm run preview # preview the production build locally
```
13 changes: 13 additions & 0 deletions frontend/demo-standalone.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/annotate-icon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Annotation Assistant - Wildlife Demo</title>
</head>
<body>
<div id="demo-root"></div>
<script type="module" src="/src/demo-main.tsx"></script>
</body>
</html>
Loading
Loading