Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9d42eb2
first pass code migration
klpoland May 6, 2026
3cc50f1
remove fragments from migrating code
klpoland May 8, 2026
600c8b9
move deprecated files
klpoland May 8, 2026
3d4462f
managers class files and clean-up js
klpoland May 8, 2026
f1fa870
repoint page js, new test coverage
klpoland May 8, 2026
4c563f5
fix ref issues
klpoland May 11, 2026
5ac5323
clean-up, clean-up
klpoland May 13, 2026
31d6a7f
move partial templates into sub folders for easier role identificatio…
klpoland May 15, 2026
2935dc8
move modal logic to backend view, clean up unused templates
klpoland May 15, 2026
5513a97
replace upload modals on capture list in partials
klpoland May 15, 2026
58e1e0d
add fallow to find dupe code, align alert/message method calls, clean…
klpoland May 18, 2026
f7f3c91
consolidate duplicate code with fallow
klpoland May 20, 2026
6abb744
consolidate test mocks
klpoland May 20, 2026
f50014d
cleanup hanging cross-file dupes
klpoland May 20, 2026
9eec5f3
pull out/break up complex functions into utility function files
klpoland May 20, 2026
42a3789
remove unused tests
klpoland May 20, 2026
ef70bd5
removed wrong template
klpoland May 20, 2026
3d10417
clean up modal method calls
klpoland May 21, 2026
5fb2b36
remove deprecated
klpoland May 21, 2026
68c032c
move action helpers under actions/
klpoland May 21, 2026
03e77d9
fixing modal/dropdown bugs
klpoland May 21, 2026
1f0a2bc
add/update tests
klpoland May 22, 2026
f57e4b8
add fallow cross-file dupe check to precommit hooks, add jest test cr…
klpoland May 22, 2026
bdebbb2
refactor upload management, remove dead-code, break out classes into …
klpoland May 22, 2026
32251f0
add js refactor skill and consolidate search mechanism
klpoland May 26, 2026
064360c
fix bugs, latency from file loading (load stats only)
klpoland May 28, 2026
0d68cc3
fix version ui bugs
klpoland May 28, 2026
d9c5eeb
hide owner from share permission options
klpoland May 28, 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
4 changes: 4 additions & 0 deletions .cursor/rules/django_javascript_implementation.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ alwaysApply: true
- Classes should follow DRY principles and avoid duplicating the functionality of existing classes.
- Javascript added to existing templates should ONLY call existing classes to initialize them so their functions are available to run in the template.
- Ignore and NEVER update files in the `deprecated/` folder.
- Differentiation of code use by asset type should be configuration-driven, NOT by the method logic-driven.
- Prefer more generic method implementations over specific, per-case basis implementations which lead to bloat.
- If you notice multiple uses of the same block of code, consider adding a utils or manager method/class to handle that instead of repeating the same code everywhere.
- When creating/naming a method, check if a method by the same name/function/use already exists. If so, point it out and suggest refactoring original method to be more generic.

## Django Template Structure

Expand Down
142 changes: 142 additions & 0 deletions .cursor/skills/gateway-static-js-refactor/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
---
name: gateway-static-js-refactor
description: Plans and executes refactors of SDS gateway browser JavaScript (gateway/sds_gateway/static/js) for brevity, lower complexity, parity, and reviewability. Uses Fallow metrics, Django template/RenderHTMLFragment rendering, DRY reuse, and django_javascript_implementation rules. Use for large JS refactors, reducing duplication, moving HTML out of JS, or when the user asks for refactor scenarios or fallow checks.
---

# Gateway static JS refactor

## When to apply

- Refactors under `gateway/sds_gateway/static/js/` (especially managers/handlers in `actions/`, `core/`, `dataset/`, `search/`, `share/`, `upload/`, `visualizations/`)
- User wants **scenarios**, a **phased plan**, or **metrics before/after**
- Removing inline HTML strings, cross-file duplication, or high-complexity hotspots
- Aligning new behavior with existing classes instead of one-off helpers

**Out of scope:** `deprecated/` (never edit). For tests after refactor, use [jest-test-writing](../jest-test-writing/SKILL.md).

## Optimization goals (in order)

1. **Functionality parity** — same user-visible behavior, API contracts, and error handling intent
2. **Human reviewability** — small, ordered commits or phases; each diff explainable in one paragraph
3. **Low method complexity** — shallow nesting, early returns, single responsibility
4. **Brevity** — fewer lines only when clarity is preserved (not golf)

## Mandatory conventions

Follow `.cursor/rules/django_javascript_implementation.mdc` in full. Non-negotiables for refactors:

| Area | Rule |
|------|------|
| JS location | Logic in `.js` files under `static/js/` subfolders; templates only **initialize** classes |
| New files | Ask before new templates; ask before new `.js` files (purpose + function list) |
| New classes | Own file in a subfolder (`actions/`, `core/`, …), not base `js/` |
| HTML | Dynamic markup → `templates/.../components/*.html` + `POST /users/render-html/` via `APIClient` / `DOMUtils`; **never** build HTML fragments in JS |
| Asset types | Configuration-driven (`constants/`, config objects), not `if (type === 'capture')` sprawl |
| Reuse | Grep for existing method/class names; **extend or generalize** before adding parallel APIs |

## Workflow

Copy and track:

```
Refactor progress:
- [ ] Baseline (fallow + identify targets)
- [ ] Propose 2–4 scenarios (user picks or hybrid)
- [ ] Implement phase 1 (smallest parity-preserving slice)
- [ ] Tests + fallow + cross-file dupes
- [ ] Implement remaining phases
- [ ] Final metrics + review notes
```

### 1. Baseline (always run from `gateway/`)

```bash
npm run fallow
npx fallow health --format human
npx fallow dupes --format human
npm run fallow:static-js
bash scripts/fallow-cross-file-dupes.sh
```

For work on a branch, scope noise:

```bash
npx fallow audit --changed-since main --format human
```

Record: worst complexity hotspots, clone groups touching your files, new dead exports.

Details: [fallow-gateway.md](fallow-gateway.md).

### 2. Discover reuse (before writing code)

- Search `static/js` for the same DOM ids, `render-html` templates, `ListRefreshManager`, `DOMUtils` helpers, and action manager patterns
- Check `constants/` (`detailsModalConfig`, `FileListConfig`, permission levels)
- Prefer widening an existing util/manager over a feature-specific function

### 3. Propose refactor scenarios

Present **2–4 options** with tradeoffs. Typical scenario types:

| Scenario | Best when | Risk |
|----------|-----------|------|
| **Extract + name** | One 200+ line method or deep nesting | Low if tests exist |
| **Consolidate duplicates** | Fallow `dupes` or copy-pasted blocks across files | Medium — watch cross-file pre-commit |
| **Config extraction** | Repeated asset-type branches | Low if config matches existing constants style |
| **Template migration** | Large `` `...html...` `` or string concatenation in JS | Medium — needs component template + view context |
| **Delegate to existing API** | Reinventing list refresh, modals, permissions | Low |
| **Split class by concern** | God-class with unrelated responsibilities | Higher — update imports/webpack if needed |

Each scenario must state: **files touched**, **parity checks**, **fallow metrics expected to improve**, and **review story** (what reviewer should skim first).

### 4. Implement (small phases)

- One logical change per phase; run tests after each phase
- After moving HTML to Django: JS only builds **context objects** and assigns `innerHTML` / `insertAdjacentHTML` from response
- When generalizing a method, keep old call sites working or update all call sites in the same phase
- Do not expand scope into unrelated templates/backend unless required for parity

### 5. Verify

From `gateway/`:

```bash
npm test
npm run fallow
npx fallow health --format human
bash scripts/fallow-cross-file-dupes.sh
```

If behavior is UI-heavy, run through affected pages (modals, lists, upload, visualizations) per team practice.

### 6. Deliverable for the user

Short summary:

- Chosen scenario and why
- Before/after notes on complexity/dupes (from fallow)
- Files changed
- Manual test checklist (bullet list)
- Any follow-ups (e.g. remove HTML fallbacks left for error paths)

## Refactor heuristics

- **Inline HTML in JS** → identify existing `users/components/*.html`; if none fits, propose **one** new component template (justify why partials/pages are wrong)
- **Duplicate API calls** → shared method on manager or thin wrapper in `core/`
- **Long switch on asset type** → move labels/URLs/permissions into config next to `detailsModalConfig` / `FileListConfig` patterns
- **Complex async chains** → extract steps with clear names; keep orchestration in one place
- **Fallback HTML in `catch`** → prefer a minimal error component template; avoid duplicating full happy-path markup

## Review checklist (for PR description)

- [ ] No new logic in Django templates except initialization
- [ ] No new files under `static/js/` root; new classes in subfolders only
- [ ] No edits under `deprecated/`
- [ ] Cross-file dupes script passes
- [ ] Jest updated or added for changed public behavior
- [ ] Parity: lists, modals, permissions, and error states manually noted

## Additional resources

- Fallow commands and CI hooks: [fallow-gateway.md](fallow-gateway.md)
- Project frontend rules: `.cursor/rules/django_javascript_implementation.mdc`
64 changes: 64 additions & 0 deletions .cursor/skills/gateway-static-js-refactor/fallow-gateway.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Fallow (gateway)

Run all commands from `gateway/` (config: `.fallowrc.json`). Ignores `sds_gateway/static/js/deprecated/**`.

## npm scripts

| Script | Purpose |
|--------|---------|
| `npm run fallow` | `fallow --summary` (overview) |
| `npm run fallow:static-js` | Dead-code per file under `static/js/` (full graph, scoped reporting) |

## Commands to use in refactors

```bash
# Summary / combined view
npm run fallow

# Cyclomatic + cognitive hotspots (prioritize splits)
npx fallow health --format human
npx fallow health --format json -q # machine-readable

# Clone groups (in-file and cross-file)
npx fallow dupes --format human
npx fallow dupes --format json -q

# Unused exports / cycles (static/js scoped via script)
npm run fallow:static-js
npx fallow dead-code --format human

# Changed-files gate (PR-sized work)
npx fallow audit --changed-since main --format human
```

## CI / pre-commit (must stay green)

```bash
bash scripts/fallow-cross-file-dupes.sh
```

Fails if any clone group spans **more than one file**. Fixing usually means shared helper or single canonical implementation.

## Interpreting results

| Signal | Typical refactor move |
|--------|------------------------|
| High cognitive/cyclomatic on one function | Extract helpers; early return; reduce branches |
| Dupes across files | Shared util or generalize existing manager method |
| Dead export after refactor | Remove export or wire usage; re-run `fallow:static-js` |
| `audit --changed-since` only on touched files | Use while iterating; run full dupes/health before merge |

## Config notes

- `ignoreExportsUsedInFile: true` — same-file-only usage may not count as “used” for export pruning; prefer explicit exports only where needed.
- Do not add `deprecated/` paths to analysis scope for fixes.

## Optional

```bash
npx fallow config # resolved config path
npx fallow list # entry points / discovered files
npx fallow explain <issue-type>
```

For agent tooling: `npx fallow schema` (CLI JSON).
126 changes: 126 additions & 0 deletions .cursor/skills/jest-test-writing/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
---
name: jest-test-writing
description: Writes and refactors Jest unit tests for browser JS (jsdom), emphasizing behavior-focused tests, shared mocks, and repo conventions. Use when adding or updating tests under gateway/sds_gateway/static/js, fixing failing Jest runs, or when the user asks for Jest test best practices.
---

# Jest test writing (SDS gateway static JS)

## When to apply

- New or changed code under `gateway/sds_gateway/static/js/`
- User asks for Jest patterns, test structure, or coverage for frontend managers/handlers
- CI/local failure from `npm test` in `gateway/`

## Run tests

From `gateway/`:

```bash
npm test
npm run test:watch
npm run test:coverage
```

Config: `sds_gateway/static/js/tests-config/jest.config.js` (jsdom, `clearMocks` + `restoreMocks`).

## File placement

| Rule | Detail |
|------|--------|
| Co-locate | `SomeManager.js` → `__tests__/SomeManager.test.js` in the same folder |
| Naming | `*.test.js` or `*.spec.js` (see `testMatch` in jest config) |
| Skip | Never add tests for `deprecated/` |

## What to test (and what not to)

**Do**

- Public methods and user-visible outcomes (DOM updates, calls to `DOMUtils`, `APIClient`, Bootstrap modal show/hide)
- Branches that encode product rules (permissions denied, missing modal, API error responses)
- Async flows: `await` the method under test, then assert mocks/callbacks

**Avoid**

- Asserting private helpers or internal call order unless order is the contract
- Tests that only `expect(x).toBeDefined()` or mirror the implementation line-for-line
- Copy-pasting 50-line mock trees—extend shared helpers instead

## Shared infrastructure (use first)

Read and reuse before inventing mocks:

| Resource | Path |
|----------|------|
| DOM/API/permissions helpers | `sds_gateway/static/js/tests-config/testHelpers.js` |
| Action-manager setups | `sds_gateway/static/js/__tests__/helpers/actionTestMocks.js` |
| Global env | `sds_gateway/static/js/tests-config/jest.setup.js` |

Common helpers:

- `setupStandardUnitTest({ useModalDomUtils, apiClientOverrides, window, getElementByIdMap })` — resets mocks, stubs `document`, sets `window.DOMUtils`
- `createMockDOMUtils` / `createMockDOMUtilsWithModals`
- `createMockAPIClient`, `createMockPermissionsManager`
- `flushMicrotasks()` — after fire-and-forget promises tied to `setTimeout(0)`
- `installDocumentGetByIdMap({ id: element })` when code uses `getElementById`

For Download/Share/Versioning action tests, prefer `setupDownloadActionTestEnvironment` / patterns in `actionTestMocks.js`.

## Structure template

```javascript
/**
* Jest tests for TargetClass
*/

import { TargetClass } from "../TargetClass.js";
import { setupStandardUnitTest, flushMicrotasks } from "../../tests-config/testHelpers.js";

describe("TargetClass", () => {
beforeEach(() => {
setupStandardUnitTest({ /* opts */ });
// Extra per-suite: bootstrap, document.body, window globals
});

test("describes behavior in plain language", async () => {
// arrange → act → assert
});
});
```

Use `require()` for helpers if the file already uses CommonJS; stay consistent within a file.

## Mocking conventions (this repo)

1. **Bootstrap modals** — set `global.bootstrap.Modal` and `Modal.getInstance` in `beforeEach` (see `ModalManager.test.js`, `actionTestMocks.installBootstrapModalMocks`).
2. **`window.DOMUtils`** — via `setupStandardUnitTest` or explicit assign; use `.mockResolvedValue()` for async UI helpers.
3. **`document`** — prefer `installDocumentGetByIdMap` or minimal stubs from testHelpers; use real `document.createElement` / `body.innerHTML` only when testing DOM wiring.
4. **Module mocks** — `jest.mock("../Dependency.js")` at top level; factory returns minimal surface the unit needs.
5. **Fetch / API** — mock `APIClient` methods or `window.fetch` with `createMockFetchResponse` / resolved shapes `{ success: true }` matching production handlers.

## Async

- Prefer `async/await` in tests over bare `.then()`.
- If code schedules work on microtasks/macrotasks without returning a promise, `await flushMicrotasks()` before assertions.
- Fake timers: use `jest.useFakeTimers()` only when testing timer logic; restore in `afterEach`.

## Assertions

- One logical behavior per test name (readable as a spec sentence).
- Assert on **arguments** to mocks when the contract is “calls X with Y” (`toHaveBeenCalledWith`).
- For errors: assert rejected promise or that `showError` / `showModalError` was invoked with expected message.

## Coverage

Global thresholds (70%) in jest config. New code should not drop coverage on touched files; add tests for new branches rather than excluding files.

## Checklist before finishing

- [ ] Test file lives in `__tests__/` next to source
- [ ] Reused `testHelpers` / `actionTestMocks` where applicable
- [ ] `beforeEach` resets DOM/globals needed for isolation
- [ ] Tests describe behavior, not implementation trivia
- [ ] `npm test` passes from `gateway/`

## More detail

See [reference.md](reference.md) for helper exports and example patterns.
Loading
Loading