Skip to content
Merged
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
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ jobs:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
echo "$HOME/.cargo/bin" >> $GITHUB_PATH

- name: Install browser test dependencies
run: |
npm ci
npx playwright install --with-deps chromium

- name: Verify assets are up to date
run: |
make clean
Expand All @@ -47,6 +52,7 @@ jobs:
run: |
cargo test
node --test tests/*.test.js
node tests/demo-browser-check.js

- name: Verify package contents
run: ./scripts/verify-package.sh
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Thumbs.db
*.iml
.zed/

# Node
node_modules/
__pycache__/

# Claude
.claude/

Expand Down
41 changes: 30 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ VERSIONED_CSS := static/sf/sf.$(VERSION).css
VERSIONED_JS := static/sf/sf.$(VERSION).js

# ============== Phony Targets ==============
.PHONY: banner help assets build build-release test test-quick test-doc test-unit test-frontend test-one \
lint fmt fmt-check clippy ci-local pre-release version package-verify \
.PHONY: banner help assets build build-release test test-quick test-doc test-unit test-frontend test-browser test-one \
lint fmt fmt-check clippy ci-local pre-release version package-verify browser-setup \
bump-patch bump-minor bump-major bump-dry demo-serve \
publish-dry publish clean watch

Expand Down Expand Up @@ -85,6 +85,7 @@ test: banner
@printf "$(ARROW) $(BOLD)Running all tests...$(RESET)\n"
@cargo test && \
node --test tests/*.test.js && \
node tests/demo-browser-check.js && \
printf "\n$(GREEN)$(CHECK) All tests passed$(RESET)\n\n" || \
(printf "\n$(RED)$(CROSS) Tests failed$(RESET)\n\n" && exit 1)

Expand All @@ -104,6 +105,10 @@ test-quick: banner
@node --test tests/*.test.js && \
printf "$(GREEN)$(CHECK) Frontend tests passed$(RESET)\n\n" || \
(printf "$(RED)$(CROSS) Frontend tests failed$(RESET)\n\n" && exit 1)
@printf "$(PROGRESS) Running browser demo smoke tests...\n"
@node tests/demo-browser-check.js && \
printf "$(GREEN)$(CHECK) Browser smoke tests passed$(RESET)\n\n" || \
(printf "$(RED)$(CROSS) Browser smoke tests failed$(RESET)\n\n" && exit 1)

test-doc:
@printf "$(PROGRESS) Running doctests...\n"
Expand All @@ -123,6 +128,18 @@ test-frontend:
printf "$(GREEN)$(CHECK) Frontend tests passed$(RESET)\n" || \
(printf "$(RED)$(CROSS) Frontend tests failed$(RESET)\n" && exit 1)

test-browser:
@printf "$(PROGRESS) Running browser demo smoke tests...\n"
@node tests/demo-browser-check.js && \
printf "$(GREEN)$(CHECK) Browser smoke tests passed$(RESET)\n" || \
(printf "$(RED)$(CROSS) Browser smoke tests failed$(RESET)\n" && exit 1)

browser-setup:
@printf "$(PROGRESS) Installing browser test dependencies...\n"
@npm ci && npx playwright install --with-deps chromium && \
printf "$(GREEN)$(CHECK) Browser test dependencies installed$(RESET)\n" || \
(printf "$(RED)$(CROSS) Browser test dependency setup failed$(RESET)\n" && exit 1)

test-one:
@printf "$(PROGRESS) Running test: $(YELLOW)$(TEST)$(RESET)\n"
@RUST_LOG=info cargo test $(TEST) -- --nocapture
Expand Down Expand Up @@ -156,20 +173,22 @@ ci-local: banner
@printf "$(CYAN)$(BOLD)║ Local CI Simulation ║$(RESET)\n"
@printf "$(CYAN)$(BOLD)╚══════════════════════════════════════════════════════════╝$(RESET)\n\n"
@printf "$(ARROW) $(BOLD)Simulating GitHub Actions CI workflow locally...$(RESET)\n\n"
@printf "$(PROGRESS) Step 1/6: Asset freshness check...\n"
@printf "$(PROGRESS) Step 1/8: Asset freshness check...\n"
@$(MAKE) assets --no-print-directory
@printf "$(PROGRESS) Step 2/6: Format check...\n"
@printf "$(PROGRESS) Step 2/8: Format check...\n"
@$(MAKE) fmt-check --no-print-directory
@printf "$(PROGRESS) Step 3/6: Build...\n"
@printf "$(PROGRESS) Step 3/8: Build...\n"
@cargo build --quiet && printf "$(GREEN)$(CHECK) Build passed$(RESET)\n"
@printf "$(PROGRESS) Step 4/6: Clippy...\n"
@printf "$(PROGRESS) Step 4/8: Clippy...\n"
@$(MAKE) clippy --no-print-directory
@printf "$(PROGRESS) Step 5/6: Doctests...\n"
@printf "$(PROGRESS) Step 5/8: Doctests...\n"
@cargo test --doc --quiet && printf "$(GREEN)$(CHECK) Doctests passed$(RESET)\n"
@printf "$(PROGRESS) Step 6/7: Unit tests...\n"
@printf "$(PROGRESS) Step 6/8: Unit tests...\n"
@cargo test --lib --quiet && printf "$(GREEN)$(CHECK) Unit tests passed$(RESET)\n"
@printf "$(PROGRESS) Step 7/7: Frontend tests...\n"
@printf "$(PROGRESS) Step 7/8: Frontend tests...\n"
@node --test tests/*.test.js && printf "$(GREEN)$(CHECK) Frontend tests passed$(RESET)\n"
@printf "$(PROGRESS) Step 8/8: Browser smoke tests...\n"
@node tests/demo-browser-check.js && printf "$(GREEN)$(CHECK) Browser smoke tests passed$(RESET)\n"
@printf "\n$(GREEN)$(BOLD)╔══════════════════════════════════════════════════════════╗$(RESET)\n"
@printf "$(GREEN)$(BOLD)║ $(CHECK) CI SIMULATION PASSED ║$(RESET)\n"
@printf "$(GREEN)$(BOLD)╚══════════════════════════════════════════════════════════╝$(RESET)\n\n"
Expand Down Expand Up @@ -209,7 +228,7 @@ pre-release: banner
@$(MAKE) fmt-check --no-print-directory
@$(MAKE) clippy --no-print-directory
@printf "$(PROGRESS) Running full test suite...\n"
@cargo test --quiet && node --test tests/*.test.js && printf "$(GREEN)$(CHECK) All tests passed$(RESET)\n"
@cargo test --quiet && node --test tests/*.test.js && node tests/demo-browser-check.js && printf "$(GREEN)$(CHECK) All tests passed$(RESET)\n"
@printf "$(PROGRESS) Dry-run publish...\n"
@cargo publish --dry-run 2>&1 | tail -1
@printf "$(PROGRESS) Verifying packaged contents...\n"
Expand Down Expand Up @@ -266,7 +285,7 @@ watch:

demo-serve: assets
@printf "$(ARROW) Serving demos at http://localhost:8000/demos/\n"
@python3 -m http.server 8000
@python3 scripts/demo_server.py

# ============== Help ==============

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,8 @@ Runnable demo fixtures live in `demos/`.
- `demos/full-surface.html` exercises the primary shipped component surface together.
- `demos/rail.html` focuses on resource cards, blocks, gauges, and changeovers.
- `make demo-serve` serves the repository at `http://localhost:8000/demos/` for local validation.
- `make test-browser` runs browser-level smoke tests against both demo fixtures.
- Run `make browser-setup` once on a machine to install the Playwright test dependency and Chromium.

## Acknowledgments

Expand Down
16 changes: 16 additions & 0 deletions demos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ Then open:
- `http://localhost:8000/demos/full-surface.html`
- `http://localhost:8000/demos/rail.html`

## Automated browser verification

Install the browser-test dependency and Chromium once:

```bash
make browser-setup
```

Then run the smoke checks:

```bash
make test-browser
```

The automated check serves the repository locally, opens both runnable demo fixtures in Chromium, fails on page or script errors, and verifies that the primary shipped UI surfaces mount successfully.

## Coverage

- `full-surface.html`: header, status bar, tabs, buttons, modal, toast, table, rail, Gantt, API guide, and footer
Expand Down
83 changes: 52 additions & 31 deletions demos/full-surface.html
Original file line number Diff line number Diff line change
Expand Up @@ -100,35 +100,11 @@
return card.el;
}

function buildGantt() {
function createGanttPanel() {
var mount = document.createElement('div');
mount.className = 'demo-gantt';

var gantt = SF.gantt.create({
gridTitle: 'Tasks',
chartTitle: 'Schedule',
viewMode: 'Half Day',
splitSizes: [38, 62],
columns: [
{ key: 'name', label: 'Task' },
{ key: 'start', label: 'Start' },
{ key: 'end', label: 'End' },
{ key: 'priority', label: 'P', render: function (task) {
return '<span class="sf-priority-badge priority-' + task.priority + '">P' + task.priority + '</span>';
} }
],
onTaskClick: function (task) {
SF.showToast({
title: 'Gantt task',
message: task.name,
variant: 'success',
delay: 1800
});
}
});

gantt.mount(mount);
gantt.setTasks([
var mounted = false;
var tasks = [
{
id: 'task-1',
name: 'Design review',
Expand Down Expand Up @@ -156,9 +132,41 @@
custom_class: 'project-color-2 priority-3',
dependencies: 'task-2'
}
]);
];

return mount;
var gantt = SF.gantt.create({
gridTitle: 'Tasks',
chartTitle: 'Schedule',
viewMode: 'Half Day',
splitSizes: [38, 62],
columns: [
{ key: 'name', label: 'Task' },
{ key: 'start', label: 'Start' },
{ key: 'end', label: 'End' },
{ key: 'priority', label: 'P', render: function (task) {
return '<span class="sf-priority-badge priority-' + task.priority + '">P' + task.priority + '</span>';
} }
],
onTaskClick: function (task) {
SF.showToast({
title: 'Gantt task',
message: task.name,
variant: 'success',
delay: 1800
});
}
});

return {
mountIfNeeded: function () {
if (mounted) return;
if (!mount.isConnected || mount.offsetWidth === 0 || mount.offsetHeight === 0) return;
gantt.mount(mount);
gantt.setTasks(tasks);
mounted = true;
},
el: mount
};
}

function buildApiGuide() {
Expand Down Expand Up @@ -186,6 +194,8 @@
}

document.addEventListener('DOMContentLoaded', function () {
var ganttPanel = createGanttPanel();

var header = SF.createHeader({
logo: '../static/sf/img/ouroboros.svg',
title: 'Planner123',
Expand All @@ -195,7 +205,14 @@
{ id: 'gantt', label: 'Gantt', icon: 'fa-chart-gantt' },
{ id: 'api', label: 'API', icon: 'fa-plug' }
],
onTabChange: function (id) { SF.showTab(id); },
onTabChange: function (id) {
SF.showTab(id);
if (id === 'gantt') {
requestAnimationFrame(function () {
ganttPanel.mountIfNeeded();
});
}
},
actions: {
onSolve: function () {
statusBar.setSolving(true);
Expand Down Expand Up @@ -280,7 +297,7 @@
var panel = document.createElement('section');
panel.className = 'demo-card';
panel.innerHTML = '<h2>Gantt</h2>';
panel.appendChild(buildGantt());
panel.appendChild(ganttPanel.el);
return panel;
})()
},
Expand All @@ -302,6 +319,10 @@
main.appendChild(tabs.el);
document.body.appendChild(main);

requestAnimationFrame(function () {
ganttPanel.mountIfNeeded();
});

document.body.appendChild(SF.createFooter({
links: [
{ label: 'Demo Index', url: './index.html' },
Expand Down
60 changes: 60 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "solverforge-ui",
"private": true,
"scripts": {
"test:browser": "node tests/demo-browser-check.js"
},
"devDependencies": {
"playwright": "^1.58.2"
}
}
Loading