Skip to content

Sprint 1 B4: Admin Page with Jobs List & Create Form#25

Merged
pipewrk merged 1 commit intomainfrom
sprint-1/b4-admin-page
Oct 1, 2025
Merged

Sprint 1 B4: Admin Page with Jobs List & Create Form#25
pipewrk merged 1 commit intomainfrom
sprint-1/b4-admin-page

Conversation

@pipewrk
Copy link
Contributor

@pipewrk pipewrk commented Oct 1, 2025

Summary

Implements Sprint 1 B4: Admin page mounted under Tools menu with list view and create form.

Closes #26

Implementation Details

New Components:

  • `app/showcase/src/admin/pages/JobsList.tsx` - React component with CRUD interface
  • `app/showcase/src/admin/index.tsx` - Mounting logic for admin app
  • Updated `app/showcase/src/index.ts` - Forces store registration before React mount

Transport Methods Completed:

  • Implemented `create()`, `update()`, `remove()` in `defineResource.ts` (previously TODOs from A3)
  • All methods use proper `@wordpress/api-fetch` transport with type safety

Store Registration:

  • Fixed registration using `createReduxStore()` pattern
  • Proper `@wordpress/data` integration with resolvers

PHP Bootstrap:

  • Updated `showcase-plugin.php` v0.3.0
  • Enqueues WordPress packages before Script Module to prevent bundling

Testing Status

  • ✅ All unit tests passing: 275/275
  • ✅ Type checking: Pass
  • ✅ Linting: Pass
  • ✅ Build successful: 15 KiB bundle
  • ✅ Manual testing: Admin page renders correctly, form displays, table shows structure

Updated Tests:

  • `defineResource.test.ts` - Updated for actual transport calls (not NotImplementedError)
  • Added proper mocking for `@wordpress/api-fetch`
  • Fixed store registration test expectations

Definition of Done

  • Component written in React using `@wordpress/element`
  • Uses `useSelect` to read from job store
  • Mounted at `/wp-admin/tools.php?page=wpk-jobs`
  • Shows loading/empty/error states
  • Create form calls `job.create()`
  • Minimal PHP bootstrap (v0.3.0 - will be replaced in Sprint 5)
  • All existing tests still passing

Manual Testing

  1. Start WordPress: `pnpm wp:start`
  2. Navigate to Tools > WP Kernel Jobs
  3. Verify form displays with fields: Label, Callback, Schedule
  4. Verify table shows "No jobs yet" (empty state)
  5. Form submission will return 501 (expected - stub endpoint)

Next Steps

  • B5: Implement actual REST endpoints (replace 501 stubs)
  • C1-C4: Complete testing phase (unit/integration/e2e + CI)

Screenshots

Admin Page Screenshot


Sprint 1 Progress: 11/14 tasks complete (79%)

Sprint 1 B4 (Admin Page) - Complete implementation demonstrating framework in WordPress admin context.

## What's New

### Admin UI Components
- **JobsList Component**: Full CRUD interface with loading/empty/error states
  - Create New Job form with title, department, location, status fields
  - All Jobs table with status badges and date formatting
  - Responsive WordPress admin styling using @wordpress/components

### Framework Integration
- **Resource → Store → React**: Complete data flow demonstration
  - Job resource auto-generates @wordpress/data store
  - React components use useSelect() for store integration
  - Store registration via createReduxStore pattern

### PHP Bootstrap (Sprint 5 will replace with mountAdmin API)
- Minimal PHP for menu registration and Script Module enqueue
- Enqueues WordPress packages (React, wp-element, wp-components, wp-data, wp-i18n)
- Renders mount point div for React application

### Build Configuration
- Single bundle approach with conditional admin loading
- TypeScript + JSX transform via @types/react
- WordPress Script Modules for native ESM loading

## Implementation Details

### Resource Client (CRUD Complete)
- Implemented create/update/remove transport methods
- All methods call transportFetch with proper paths and data
- DELETE returns void, POST/PUT return response data

### Store Registration
- Uses wp.data.createReduxStore for proper store descriptor
- Lazy initialization on first store access
- Auto-registers with @wordpress/data when available

### Component Architecture
- Static imports for bundled admin code
- Conditional mounting via getElementById check
- Error boundaries via try/catch for mount failures

## Testing
- ✅ 275/275 tests passing
- ✅ Fixed create/update/remove method tests with proper mocking
- ✅ Updated store registration test for createReduxStore pattern
- ✅ Manual testing: admin page renders successfully with form and table

## Files Changed
- app/showcase/src/admin/index.tsx - Admin mount point
- app/showcase/src/admin/pages/JobsList.tsx - Jobs CRUD UI
- app/showcase/src/index.ts - Main entry with store initialization
- app/showcase/showcase-plugin.php - PHP bootstrap (v0.3.0)
- packages/kernel/src/resource/defineResource.ts - Store registration via createReduxStore
- packages/kernel/src/resource/__tests__/defineResource.test.ts - Updated tests

## Next Steps
- Sprint 1 B5: REST endpoint implementation (replace 501 stubs)
- Sprint 1 C1-C4: Testing phase (unit, integration, E2E, CI)

Co-authored-by: GitHub Copilot <[email protected]>
Copilot AI review requested due to automatic review settings October 1, 2025 08:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements Sprint 1 B4, completing the admin page with a full CRUD interface for jobs. The implementation shifts from TODO placeholders to functional transport methods and introduces a React-based admin interface.

  • Completes the defineResource transport methods (create, update, remove) by replacing NotImplementedError stubs with actual @wordpress/api-fetch calls
  • Adds a React admin page with jobs list display and create form using @wordpress/components
  • Updates store registration to use the proper createReduxStore pattern for WordPress data integration

Reviewed Changes

Copilot reviewed 11 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/kernel/src/resource/defineResource.ts Implements actual transport calls for create/update/remove methods and fixes store registration
packages/kernel/src/resource/tests/defineResource.test.ts Updates tests to mock actual transport calls instead of expecting NotImplementedError
app/showcase/src/admin/pages/JobsList.tsx New React component providing jobs list view and create form
app/showcase/src/admin/index.tsx Admin mounting logic for React app
app/showcase/src/index.ts Forces store registration and adds admin mounting logic
app/showcase/showcase-plugin.php Updates PHP bootstrap to v0.3.0 with admin menu and dependency management
package.json Adds React type dependencies
app/showcase/webpack.config.cjs New webpack config for WordPress externals
app/showcase/tsconfig.json Adds React JSX configuration
app/showcase/package.json Adds WordPress package dependencies and updates build scripts
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment on lines +257 to +264
client.create = async (data: Partial<T>): Promise<T> => {
const response = await transportFetch<T>({
path: config.routes.create!.path,
method: 'POST',
data,
});

return response.data;
Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The response object structure assumes a data property, but transportFetch may return the data directly. This could cause runtime errors if the API response format differs from expectations.

Copilot uses AI. Check for mistakes.
method: config.routes.update!.method as 'PUT' | 'PATCH',
data,
});

Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as create method - assumes response.data structure without verification that transportFetch returns an object with a data property.

Suggested change
if (!response || typeof response !== 'object' || !('data' in response)) {
throw new KernelError('Malformed response: missing data property');
}

Copilot uses AI. Check for mistakes.
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { job } from '../../resources/job';
import type { Job } from '../../../types/job.js';
Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import path '../../../types/job.js' appears to reference a file outside the current directory structure. This will likely cause a module resolution error.

Suggested change
import type { Job } from '../../../types/job.js';
import type { Job } from '../../../types/job';

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +54
const { jobsResponse, isLoading, error } = useSelect((select) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const store = select(job.storeKey) as any;
Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using any type defeats TypeScript's type safety. Consider defining proper types for the store selectors or using a more specific type annotation.

Suggested change
const { jobsResponse, isLoading, error } = useSelect((select) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const store = select(job.storeKey) as any;
interface JobStoreSelectors {
getList: () => { items: Job[]; total: number } | undefined;
isResolving: (selectorName: string, args: unknown[]) => boolean;
getResolutionError: (selectorName: string, args: unknown[]) => unknown;
}
const { jobsResponse, isLoading, error } = useSelect((select) => {
const store = select(job.storeKey) as JobStoreSelectors;

Copilot uses AI. Check for mistakes.
})
}
disabled={isCreating}
/>{' '}
Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Extra space character after the JSX closing tag is unnecessary and could be removed for cleaner code.

Suggested change
/>{' '}
/>

Copilot uses AI. Check for mistakes.
@pipewrk pipewrk merged commit aa02758 into main Oct 1, 2025
6 checks passed
@pipewrk pipewrk deleted the sprint-1/b4-admin-page branch October 5, 2025 01:48
pipewrk added a commit that referenced this pull request Nov 8, 2025
Sprint 1 B4: Admin Page with Jobs List & Create Form
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants