@inf-minds/jobs-ui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ConnectionStatus.d.ts +33 -0
- package/dist/components/ConnectionStatus.js +19 -0
- package/dist/components/CreateJobForm.d.ts +34 -0
- package/dist/components/CreateJobForm.js +45 -0
- package/dist/components/Dashboard.d.ts +56 -0
- package/dist/components/Dashboard.js +30 -0
- package/dist/components/JobCard.d.ts +30 -0
- package/dist/components/JobCard.js +21 -0
- package/dist/components/JobEventLog.d.ts +37 -0
- package/dist/components/JobEventLog.js +41 -0
- package/dist/components/JobFilters.d.ts +36 -0
- package/dist/components/JobFilters.js +21 -0
- package/dist/components/JobList.d.ts +35 -0
- package/dist/components/JobList.js +25 -0
- package/dist/components/JobProgress.d.ts +44 -0
- package/dist/components/JobProgress.js +35 -0
- package/dist/components/JobStatusBadge.d.ts +42 -0
- package/dist/components/JobStatusBadge.js +32 -0
- package/dist/components/index.d.ts +9 -0
- package/dist/components/index.js +11 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/use-connection.d.ts +34 -0
- package/dist/hooks/use-connection.js +66 -0
- package/dist/hooks/use-job-list.d.ts +70 -0
- package/dist/hooks/use-job-list.js +64 -0
- package/dist/hooks/use-job-stream.d.ts +58 -0
- package/dist/hooks/use-job-stream.js +73 -0
- package/dist/hooks/use-job.d.ts +56 -0
- package/dist/hooks/use-job.js +64 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +8 -0
- package/dist/store/index.d.ts +2 -0
- package/dist/store/index.js +3 -0
- package/dist/store/job-stream-store.d.ts +23 -0
- package/dist/store/job-stream-store.js +161 -0
- package/dist/store/types.d.ts +72 -0
- package/dist/store/types.js +3 -0
- package/dist/styles/components.css +223 -0
- package/dist/styles/index.d.ts +25 -0
- package/dist/styles/index.js +27 -0
- package/dist/styles/preset.d.ts +19 -0
- package/dist/styles/preset.js +52 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/renderers.d.ts +55 -0
- package/dist/types/renderers.js +3 -0
- package/package.json +54 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Props for ConnectionStatus component.
|
|
3
|
+
*/
|
|
4
|
+
export interface ConnectionStatusProps {
|
|
5
|
+
/** Whether the connection is active */
|
|
6
|
+
connected: boolean;
|
|
7
|
+
/** Error message if connection failed */
|
|
8
|
+
error?: string;
|
|
9
|
+
/** Whether reconnection is in progress */
|
|
10
|
+
reconnecting?: boolean;
|
|
11
|
+
/** Label for connected state */
|
|
12
|
+
connectedLabel?: string;
|
|
13
|
+
/** Label for disconnected state */
|
|
14
|
+
disconnectedLabel?: string;
|
|
15
|
+
/** Custom class name */
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Connection status indicator component.
|
|
20
|
+
*
|
|
21
|
+
* Displays the current connection state with optional error
|
|
22
|
+
* and reconnecting indicators. Uses data attributes for styling.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <ConnectionStatus
|
|
27
|
+
* connected={connected}
|
|
28
|
+
* error={error}
|
|
29
|
+
* reconnecting={!connected && !error}
|
|
30
|
+
* />
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function ConnectionStatus({ connected, error, reconnecting, connectedLabel, disconnectedLabel, className, }: ConnectionStatusProps): JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Connection status indicator component.
|
|
4
|
+
*
|
|
5
|
+
* Displays the current connection state with optional error
|
|
6
|
+
* and reconnecting indicators. Uses data attributes for styling.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* <ConnectionStatus
|
|
11
|
+
* connected={connected}
|
|
12
|
+
* error={error}
|
|
13
|
+
* reconnecting={!connected && !error}
|
|
14
|
+
* />
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function ConnectionStatus({ connected, error, reconnecting, connectedLabel = 'Connected', disconnectedLabel = 'Disconnected', className, }) {
|
|
18
|
+
return (_jsxs("div", { "data-connection-status": true, "data-connected": connected, className: className, children: [_jsx("span", { "data-status-text": true, children: connected ? connectedLabel : disconnectedLabel }), !connected && reconnecting && (_jsx("span", { "data-reconnecting": true, children: "Reconnecting..." })), error && _jsx("span", { "data-error": true, children: error })] }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { JobRendererRegistry } from '../types/renderers.js';
|
|
2
|
+
/**
|
|
3
|
+
* Props for CreateJobForm component.
|
|
4
|
+
*/
|
|
5
|
+
export interface CreateJobFormProps {
|
|
6
|
+
/** Available job types */
|
|
7
|
+
jobTypes: string[];
|
|
8
|
+
/** Registry of renderers for job-specific form fields */
|
|
9
|
+
renderers: JobRendererRegistry;
|
|
10
|
+
/** Callback when form is submitted with valid input */
|
|
11
|
+
onSubmit: (jobType: string, input: unknown) => void;
|
|
12
|
+
/** Whether the form is disabled */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Whether submission is in progress */
|
|
15
|
+
loading?: boolean;
|
|
16
|
+
/** Custom class name */
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Form for creating new jobs.
|
|
21
|
+
*
|
|
22
|
+
* Uses the renderer plugin system to display job-type-specific
|
|
23
|
+
* form fields and validation. Uses data attributes for styling.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* <CreateJobForm
|
|
28
|
+
* jobTypes={['haiku', 'summary']}
|
|
29
|
+
* renderers={renderers}
|
|
30
|
+
* onSubmit={(type, input) => createJob(type, input)}
|
|
31
|
+
* />
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function CreateJobForm({ jobTypes, renderers, onSubmit, disabled, loading, className, }: CreateJobFormProps): JSX.Element;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// ABOUTME: Form component for creating new jobs
|
|
3
|
+
// ABOUTME: Uses renderer plugin system for job-type-specific form fields
|
|
4
|
+
import { useState, useRef } from 'react';
|
|
5
|
+
/**
|
|
6
|
+
* Form for creating new jobs.
|
|
7
|
+
*
|
|
8
|
+
* Uses the renderer plugin system to display job-type-specific
|
|
9
|
+
* form fields and validation. Uses data attributes for styling.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <CreateJobForm
|
|
14
|
+
* jobTypes={['haiku', 'summary']}
|
|
15
|
+
* renderers={renderers}
|
|
16
|
+
* onSubmit={(type, input) => createJob(type, input)}
|
|
17
|
+
* />
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function CreateJobForm({ jobTypes, renderers, onSubmit, disabled = false, loading = false, className, }) {
|
|
21
|
+
const [selectedType, setSelectedType] = useState(jobTypes[0] || '');
|
|
22
|
+
const [error, setError] = useState(null);
|
|
23
|
+
const formRef = useRef(null);
|
|
24
|
+
const renderer = renderers[selectedType];
|
|
25
|
+
const handleSubmit = (e) => {
|
|
26
|
+
e.preventDefault();
|
|
27
|
+
setError(null);
|
|
28
|
+
if (!renderer || !formRef.current) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const formData = new FormData(formRef.current);
|
|
32
|
+
const result = renderer.validateInput(formData);
|
|
33
|
+
if (result && typeof result === 'object' && 'error' in result) {
|
|
34
|
+
setError(result.error);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
onSubmit(selectedType, result);
|
|
38
|
+
};
|
|
39
|
+
const handleTypeChange = (e) => {
|
|
40
|
+
setSelectedType(e.target.value);
|
|
41
|
+
setError(null);
|
|
42
|
+
};
|
|
43
|
+
const isDisabled = disabled || loading;
|
|
44
|
+
return (_jsxs("form", { ref: formRef, "data-create-job-form": true, "data-disabled": isDisabled || undefined, className: className, onSubmit: handleSubmit, children: [_jsx("select", { "aria-label": "Job type", value: selectedType, onChange: handleTypeChange, disabled: isDisabled, "data-job-type-select": true, children: jobTypes.map((type) => (_jsx("option", { value: type, children: type }, type))) }), _jsx("div", { "data-form-fields": true, children: renderer ? (renderer.renderFormFields()) : (_jsx("p", { children: "No configuration available for this job type" })) }), error && _jsx("div", { "data-form-error": true, children: error }), _jsx("button", { type: "submit", disabled: isDisabled, children: loading ? 'Creating...' : 'Create Job' })] }));
|
|
45
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for Dashboard component.
|
|
4
|
+
*/
|
|
5
|
+
export interface DashboardProps {
|
|
6
|
+
/** Content for the header section */
|
|
7
|
+
header?: ReactNode;
|
|
8
|
+
/** Content for the sidebar section */
|
|
9
|
+
sidebar?: ReactNode;
|
|
10
|
+
/** Content for the footer section */
|
|
11
|
+
footer?: ReactNode;
|
|
12
|
+
/** Main content */
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
/** Custom class name */
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Props for Dashboard.Section component.
|
|
19
|
+
*/
|
|
20
|
+
export interface DashboardSectionProps {
|
|
21
|
+
/** Section title */
|
|
22
|
+
title: string;
|
|
23
|
+
/** Section content */
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
/** Whether section is collapsible */
|
|
26
|
+
collapsible?: boolean;
|
|
27
|
+
/** Custom class name */
|
|
28
|
+
className?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Dashboard section subcomponent.
|
|
32
|
+
*/
|
|
33
|
+
declare function DashboardSection({ title, children, collapsible, className, }: DashboardSectionProps): JSX.Element;
|
|
34
|
+
/**
|
|
35
|
+
* Dashboard layout component.
|
|
36
|
+
*
|
|
37
|
+
* Provides a flexible layout structure with optional header, sidebar,
|
|
38
|
+
* main content area, and footer. Uses data attributes for styling.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* <Dashboard
|
|
43
|
+
* header={<h1>Jobs Dashboard</h1>}
|
|
44
|
+
* sidebar={<Navigation />}
|
|
45
|
+
* >
|
|
46
|
+
* <Dashboard.Section title="Active Jobs">
|
|
47
|
+
* <JobList jobs={jobs} />
|
|
48
|
+
* </Dashboard.Section>
|
|
49
|
+
* </Dashboard>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function Dashboard({ header, sidebar, footer, children, className, }: DashboardProps): JSX.Element;
|
|
53
|
+
export declare namespace Dashboard {
|
|
54
|
+
var Section: typeof DashboardSection;
|
|
55
|
+
}
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Dashboard section subcomponent.
|
|
4
|
+
*/
|
|
5
|
+
function DashboardSection({ title, children, collapsible, className, }) {
|
|
6
|
+
return (_jsxs("section", { "data-dashboard-section": true, "data-collapsible": collapsible || undefined, "aria-label": title, className: className, children: [_jsx("h3", { children: title }), children] }));
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Dashboard layout component.
|
|
10
|
+
*
|
|
11
|
+
* Provides a flexible layout structure with optional header, sidebar,
|
|
12
|
+
* main content area, and footer. Uses data attributes for styling.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <Dashboard
|
|
17
|
+
* header={<h1>Jobs Dashboard</h1>}
|
|
18
|
+
* sidebar={<Navigation />}
|
|
19
|
+
* >
|
|
20
|
+
* <Dashboard.Section title="Active Jobs">
|
|
21
|
+
* <JobList jobs={jobs} />
|
|
22
|
+
* </Dashboard.Section>
|
|
23
|
+
* </Dashboard>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function Dashboard({ header, sidebar, footer, children, className, }) {
|
|
27
|
+
return (_jsxs("div", { "data-dashboard": true, "data-has-sidebar": sidebar ? true : undefined, "data-has-header": header ? true : undefined, className: className, children: [header && _jsx("header", { "data-dashboard-header": true, children: header }), _jsxs("div", { "data-dashboard-body": true, children: [sidebar && _jsx("aside", { "data-dashboard-sidebar": true, children: sidebar }), _jsx("main", { "data-dashboard-main": true, children: children })] }), footer && _jsx("footer", { "data-dashboard-footer": true, children: footer })] }));
|
|
28
|
+
}
|
|
29
|
+
// Attach Section as a static property
|
|
30
|
+
Dashboard.Section = DashboardSection;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { JobData, JobTypeRenderer } from '../types/renderers.js';
|
|
2
|
+
/**
|
|
3
|
+
* Props for JobCard component.
|
|
4
|
+
*/
|
|
5
|
+
export interface JobCardProps<TInput = unknown, TOutput = unknown> {
|
|
6
|
+
/** Job data to display */
|
|
7
|
+
job: JobData<TInput, TOutput>;
|
|
8
|
+
/** Custom renderer for job-specific content */
|
|
9
|
+
renderer?: JobTypeRenderer<TInput, TOutput>;
|
|
10
|
+
/** Callback when retry button is clicked */
|
|
11
|
+
onRetry?: (jobId: string) => void;
|
|
12
|
+
/** Custom class name */
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Generic job card component.
|
|
17
|
+
*
|
|
18
|
+
* Displays job status, content, errors, and retry functionality.
|
|
19
|
+
* Uses data attributes for CSS styling.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <JobCard
|
|
24
|
+
* job={job}
|
|
25
|
+
* renderer={myRenderer}
|
|
26
|
+
* onRetry={(id) => handleRetry(id)}
|
|
27
|
+
* />
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function JobCard<TInput = unknown, TOutput = unknown>({ job, renderer, onRetry, className, }: JobCardProps<TInput, TOutput>): JSX.Element;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { JobStatusBadge } from './JobStatusBadge.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generic job card component.
|
|
5
|
+
*
|
|
6
|
+
* Displays job status, content, errors, and retry functionality.
|
|
7
|
+
* Uses data attributes for CSS styling.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <JobCard
|
|
12
|
+
* job={job}
|
|
13
|
+
* renderer={myRenderer}
|
|
14
|
+
* onRetry={(id) => handleRetry(id)}
|
|
15
|
+
* />
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function JobCard({ job, renderer, onRetry, className, }) {
|
|
19
|
+
const isFailed = job.status === 'failed';
|
|
20
|
+
return (_jsxs("div", { "data-job-card": true, "data-status": job.status, className: className, children: [_jsxs("div", { "data-job-card-header": true, children: [_jsx("span", { "data-job-id": true, children: job.id }), _jsx(JobStatusBadge, { status: job.status })] }), _jsx("div", { "data-job-card-content": true, children: renderer ? (renderer.renderContent(job)) : (job.output !== undefined && (_jsx("pre", { children: JSON.stringify(job.output, null, 2) }))) }), job.error && (_jsx("div", { "data-job-card-error": true, children: job.error })), isFailed && onRetry && (_jsx("div", { "data-job-card-actions": true, children: _jsx("button", { onClick: () => onRetry(job.id), "data-retry-button": true, children: "Retry" }) }))] }));
|
|
21
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for JobEventLog component.
|
|
4
|
+
*/
|
|
5
|
+
export interface JobEventLogProps<TEvent> {
|
|
6
|
+
/** Events to display */
|
|
7
|
+
events: TEvent[];
|
|
8
|
+
/** Render function for each event */
|
|
9
|
+
renderEvent: (event: TEvent, index: number) => React.ReactNode;
|
|
10
|
+
/** Auto-scroll to bottom when new events arrive (default: true) */
|
|
11
|
+
autoScroll?: boolean;
|
|
12
|
+
/** Maximum height - enables scrolling */
|
|
13
|
+
maxHeight?: string | number;
|
|
14
|
+
/** Custom class name */
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Scrollable event log component.
|
|
19
|
+
*
|
|
20
|
+
* Unstyled by default - use CSS to style via data attributes:
|
|
21
|
+
* - `[data-job-event-log]` - container
|
|
22
|
+
* - `[data-job-event-log-empty]` - shown when no events
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <JobEventLog
|
|
27
|
+
* events={events}
|
|
28
|
+
* maxHeight={400}
|
|
29
|
+
* renderEvent={(event) => (
|
|
30
|
+
* <div key={event.id}>
|
|
31
|
+
* <span>{event.type}</span>: {event.message}
|
|
32
|
+
* </div>
|
|
33
|
+
* )}
|
|
34
|
+
* />
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function JobEventLog<TEvent>({ events, renderEvent, autoScroll, maxHeight, className, }: JobEventLogProps<TEvent>): JSX.Element;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// ABOUTME: JobEventLog component for displaying job events
|
|
3
|
+
// ABOUTME: Supports auto-scroll and custom event rendering
|
|
4
|
+
import { useRef, useEffect } from 'react';
|
|
5
|
+
/**
|
|
6
|
+
* Scrollable event log component.
|
|
7
|
+
*
|
|
8
|
+
* Unstyled by default - use CSS to style via data attributes:
|
|
9
|
+
* - `[data-job-event-log]` - container
|
|
10
|
+
* - `[data-job-event-log-empty]` - shown when no events
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* <JobEventLog
|
|
15
|
+
* events={events}
|
|
16
|
+
* maxHeight={400}
|
|
17
|
+
* renderEvent={(event) => (
|
|
18
|
+
* <div key={event.id}>
|
|
19
|
+
* <span>{event.type}</span>: {event.message}
|
|
20
|
+
* </div>
|
|
21
|
+
* )}
|
|
22
|
+
* />
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function JobEventLog({ events, renderEvent, autoScroll = true, maxHeight, className, }) {
|
|
26
|
+
const containerRef = useRef(null);
|
|
27
|
+
const prevEventsLengthRef = useRef(events.length);
|
|
28
|
+
// Auto-scroll when new events arrive
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (autoScroll && events.length > prevEventsLengthRef.current && containerRef.current) {
|
|
31
|
+
containerRef.current.scrollTop = containerRef.current.scrollHeight;
|
|
32
|
+
}
|
|
33
|
+
prevEventsLengthRef.current = events.length;
|
|
34
|
+
}, [events.length, autoScroll]);
|
|
35
|
+
const style = {};
|
|
36
|
+
if (maxHeight !== undefined) {
|
|
37
|
+
style.maxHeight = typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight;
|
|
38
|
+
style.overflowY = 'auto';
|
|
39
|
+
}
|
|
40
|
+
return (_jsx("div", { ref: containerRef, "data-job-event-log": true, className: className, style: style, children: events.length === 0 ? (_jsx("div", { "data-job-event-log-empty": true, children: "No events yet" })) : (events.map((event, index) => renderEvent(event, index))) }));
|
|
41
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { JobStatus } from './JobStatusBadge.js';
|
|
2
|
+
/**
|
|
3
|
+
* Props for JobFilters component.
|
|
4
|
+
*/
|
|
5
|
+
export interface JobFiltersProps {
|
|
6
|
+
/** Current status filter value */
|
|
7
|
+
statusFilter: JobStatus | 'all';
|
|
8
|
+
/** Current type filter value */
|
|
9
|
+
typeFilter: string | 'all';
|
|
10
|
+
/** Available job types for filtering */
|
|
11
|
+
availableTypes: string[];
|
|
12
|
+
/** Callback when status filter changes */
|
|
13
|
+
onStatusChange: (status: JobStatus | 'all') => void;
|
|
14
|
+
/** Callback when type filter changes */
|
|
15
|
+
onTypeChange: (type: string | 'all') => void;
|
|
16
|
+
/** Custom class name */
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Filter controls for job lists.
|
|
21
|
+
*
|
|
22
|
+
* Provides dropdown filters for job status and type.
|
|
23
|
+
* Uses data attributes for CSS styling.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* <JobFilters
|
|
28
|
+
* statusFilter={statusFilter}
|
|
29
|
+
* typeFilter={typeFilter}
|
|
30
|
+
* availableTypes={['haiku', 'summary']}
|
|
31
|
+
* onStatusChange={setStatusFilter}
|
|
32
|
+
* onTypeChange={setTypeFilter}
|
|
33
|
+
* />
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function JobFilters({ statusFilter, typeFilter, availableTypes, onStatusChange, onTypeChange, className, }: JobFiltersProps): JSX.Element;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Filter controls for job lists.
|
|
4
|
+
*
|
|
5
|
+
* Provides dropdown filters for job status and type.
|
|
6
|
+
* Uses data attributes for CSS styling.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* <JobFilters
|
|
11
|
+
* statusFilter={statusFilter}
|
|
12
|
+
* typeFilter={typeFilter}
|
|
13
|
+
* availableTypes={['haiku', 'summary']}
|
|
14
|
+
* onStatusChange={setStatusFilter}
|
|
15
|
+
* onTypeChange={setTypeFilter}
|
|
16
|
+
* />
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function JobFilters({ statusFilter, typeFilter, availableTypes, onStatusChange, onTypeChange, className, }) {
|
|
20
|
+
return (_jsxs("div", { "data-job-filters": true, className: className, children: [_jsxs("select", { "aria-label": "Filter by status", value: statusFilter, onChange: (e) => onStatusChange(e.target.value), "data-filter-status": true, children: [_jsx("option", { value: "all", children: "All Statuses" }), _jsx("option", { value: "pending", children: "Pending" }), _jsx("option", { value: "running", children: "Running" }), _jsx("option", { value: "completed", children: "Completed" }), _jsx("option", { value: "failed", children: "Failed" })] }), _jsxs("select", { "aria-label": "Filter by type", value: typeFilter, onChange: (e) => onTypeChange(e.target.value), "data-filter-type": true, children: [_jsx("option", { value: "all", children: "All Types" }), availableTypes.map((type) => (_jsx("option", { value: type, children: type }, type)))] })] }));
|
|
21
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { JobData, JobRendererRegistry } from '../types/renderers.js';
|
|
2
|
+
/**
|
|
3
|
+
* Props for JobList component.
|
|
4
|
+
*/
|
|
5
|
+
export interface JobListProps {
|
|
6
|
+
/** Jobs to display */
|
|
7
|
+
jobs: JobData[];
|
|
8
|
+
/** Registry of renderers for different job types */
|
|
9
|
+
renderers?: JobRendererRegistry;
|
|
10
|
+
/** Callback when retry button is clicked */
|
|
11
|
+
onRetry?: (jobId: string) => void;
|
|
12
|
+
/** Title for the section */
|
|
13
|
+
title?: string;
|
|
14
|
+
/** Message to display when list is empty */
|
|
15
|
+
emptyMessage?: string;
|
|
16
|
+
/** Custom class name */
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Job list component with grid layout.
|
|
21
|
+
*
|
|
22
|
+
* Displays a list of jobs with optional title and empty state handling.
|
|
23
|
+
* Uses data attributes for CSS styling.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* <JobList
|
|
28
|
+
* jobs={jobs}
|
|
29
|
+
* title="Active Jobs"
|
|
30
|
+
* renderers={{ 'haiku': haikuRenderer }}
|
|
31
|
+
* onRetry={(id) => handleRetry(id)}
|
|
32
|
+
* />
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function JobList({ jobs, renderers, onRetry, title, emptyMessage, className, }: JobListProps): JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { JobCard } from './JobCard.js';
|
|
3
|
+
/**
|
|
4
|
+
* Job list component with grid layout.
|
|
5
|
+
*
|
|
6
|
+
* Displays a list of jobs with optional title and empty state handling.
|
|
7
|
+
* Uses data attributes for CSS styling.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <JobList
|
|
12
|
+
* jobs={jobs}
|
|
13
|
+
* title="Active Jobs"
|
|
14
|
+
* renderers={{ 'haiku': haikuRenderer }}
|
|
15
|
+
* onRetry={(id) => handleRetry(id)}
|
|
16
|
+
* />
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function JobList({ jobs, renderers, onRetry, title, emptyMessage = 'No jobs', className, }) {
|
|
20
|
+
// Empty state
|
|
21
|
+
if (jobs.length === 0) {
|
|
22
|
+
return (_jsx("div", { "data-job-list-empty": true, className: className, children: emptyMessage }));
|
|
23
|
+
}
|
|
24
|
+
return (_jsxs("section", { "data-job-list": true, className: className, children: [title && (_jsxs("h2", { "data-job-list-title": true, children: [title, " (", jobs.length, ")"] })), _jsx("div", { "data-job-list-grid": true, children: jobs.map((job) => (_jsx(JobCard, { job: job, renderer: renderers?.[job.type], onRetry: onRetry }, job.id))) })] }));
|
|
25
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Props for JobProgress component.
|
|
3
|
+
*/
|
|
4
|
+
export interface JobProgressProps {
|
|
5
|
+
/** Progress value (0.0 - 1.0) */
|
|
6
|
+
value: number;
|
|
7
|
+
/** Optional message */
|
|
8
|
+
message?: string;
|
|
9
|
+
/** Show percentage label */
|
|
10
|
+
showLabel?: boolean;
|
|
11
|
+
/** Custom class name */
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Simple progress bar component.
|
|
16
|
+
*
|
|
17
|
+
* Unstyled by default - use CSS to style via data attributes:
|
|
18
|
+
* - `[data-job-progress]` - container
|
|
19
|
+
* - `[data-job-progress-bar]` - the fill bar
|
|
20
|
+
* - `[data-job-progress-label]` - the percentage label
|
|
21
|
+
* - `[data-job-progress-message]` - the message
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* <JobProgress value={0.5} message="Processing..." showLabel />
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example CSS
|
|
29
|
+
* ```css
|
|
30
|
+
* [data-job-progress] {
|
|
31
|
+
* height: 8px;
|
|
32
|
+
* background: #e5e7eb;
|
|
33
|
+
* border-radius: 4px;
|
|
34
|
+
* overflow: hidden;
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* [data-job-progress-bar] {
|
|
38
|
+
* height: 100%;
|
|
39
|
+
* background: #3b82f6;
|
|
40
|
+
* transition: width 0.3s ease;
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function JobProgress({ value, message, showLabel, className, }: JobProgressProps): JSX.Element;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Simple progress bar component.
|
|
4
|
+
*
|
|
5
|
+
* Unstyled by default - use CSS to style via data attributes:
|
|
6
|
+
* - `[data-job-progress]` - container
|
|
7
|
+
* - `[data-job-progress-bar]` - the fill bar
|
|
8
|
+
* - `[data-job-progress-label]` - the percentage label
|
|
9
|
+
* - `[data-job-progress-message]` - the message
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <JobProgress value={0.5} message="Processing..." showLabel />
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example CSS
|
|
17
|
+
* ```css
|
|
18
|
+
* [data-job-progress] {
|
|
19
|
+
* height: 8px;
|
|
20
|
+
* background: #e5e7eb;
|
|
21
|
+
* border-radius: 4px;
|
|
22
|
+
* overflow: hidden;
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* [data-job-progress-bar] {
|
|
26
|
+
* height: 100%;
|
|
27
|
+
* background: #3b82f6;
|
|
28
|
+
* transition: width 0.3s ease;
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function JobProgress({ value, message, showLabel = false, className, }) {
|
|
33
|
+
const percentage = Math.round(Math.max(0, Math.min(1, value)) * 100);
|
|
34
|
+
return (_jsxs("div", { "data-job-progress": true, className: className, children: [_jsx("div", { "data-job-progress-bar": true, style: { width: `${percentage}%` }, role: "progressbar", "aria-valuenow": percentage, "aria-valuemin": 0, "aria-valuemax": 100 }), showLabel && (_jsxs("span", { "data-job-progress-label": true, children: [percentage, "%"] })), message && (_jsx("span", { "data-job-progress-message": true, children: message }))] }));
|
|
35
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job status values.
|
|
3
|
+
*/
|
|
4
|
+
export type JobStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
5
|
+
/**
|
|
6
|
+
* Props for JobStatusBadge component.
|
|
7
|
+
*/
|
|
8
|
+
export interface JobStatusBadgeProps {
|
|
9
|
+
/** Job status */
|
|
10
|
+
status: JobStatus;
|
|
11
|
+
/** Custom class name */
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Status badge component.
|
|
16
|
+
*
|
|
17
|
+
* Unstyled by default - use CSS to style via data attributes:
|
|
18
|
+
* - `[data-job-status]` - container
|
|
19
|
+
* - `[data-status="pending"]`, `[data-status="running"]`, etc. - for status-specific styles
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <JobStatusBadge status="running" />
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example CSS
|
|
27
|
+
* ```css
|
|
28
|
+
* [data-job-status] {
|
|
29
|
+
* padding: 2px 8px;
|
|
30
|
+
* border-radius: 4px;
|
|
31
|
+
* font-size: 12px;
|
|
32
|
+
* font-weight: 500;
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* [data-status="pending"] { background: #fef3c7; color: #92400e; }
|
|
36
|
+
* [data-status="running"] { background: #dbeafe; color: #1e40af; }
|
|
37
|
+
* [data-status="completed"] { background: #d1fae5; color: #065f46; }
|
|
38
|
+
* [data-status="failed"] { background: #fee2e2; color: #991b1b; }
|
|
39
|
+
* [data-status="cancelled"] { background: #f3f4f6; color: #4b5563; }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function JobStatusBadge({ status, className, }: JobStatusBadgeProps): JSX.Element;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Status badge component.
|
|
4
|
+
*
|
|
5
|
+
* Unstyled by default - use CSS to style via data attributes:
|
|
6
|
+
* - `[data-job-status]` - container
|
|
7
|
+
* - `[data-status="pending"]`, `[data-status="running"]`, etc. - for status-specific styles
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <JobStatusBadge status="running" />
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @example CSS
|
|
15
|
+
* ```css
|
|
16
|
+
* [data-job-status] {
|
|
17
|
+
* padding: 2px 8px;
|
|
18
|
+
* border-radius: 4px;
|
|
19
|
+
* font-size: 12px;
|
|
20
|
+
* font-weight: 500;
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* [data-status="pending"] { background: #fef3c7; color: #92400e; }
|
|
24
|
+
* [data-status="running"] { background: #dbeafe; color: #1e40af; }
|
|
25
|
+
* [data-status="completed"] { background: #d1fae5; color: #065f46; }
|
|
26
|
+
* [data-status="failed"] { background: #fee2e2; color: #991b1b; }
|
|
27
|
+
* [data-status="cancelled"] { background: #f3f4f6; color: #4b5563; }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function JobStatusBadge({ status, className, }) {
|
|
31
|
+
return (_jsx("span", { "data-job-status": true, "data-status": status, className: className, children: status }));
|
|
32
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { JobProgress, type JobProgressProps } from './JobProgress.js';
|
|
2
|
+
export { JobEventLog, type JobEventLogProps } from './JobEventLog.js';
|
|
3
|
+
export { JobStatusBadge, type JobStatusBadgeProps, type JobStatus } from './JobStatusBadge.js';
|
|
4
|
+
export { JobCard, type JobCardProps } from './JobCard.js';
|
|
5
|
+
export { JobList, type JobListProps } from './JobList.js';
|
|
6
|
+
export { JobFilters, type JobFiltersProps } from './JobFilters.js';
|
|
7
|
+
export { ConnectionStatus, type ConnectionStatusProps } from './ConnectionStatus.js';
|
|
8
|
+
export { CreateJobForm, type CreateJobFormProps } from './CreateJobForm.js';
|
|
9
|
+
export { Dashboard, type DashboardProps, type DashboardSectionProps } from './Dashboard.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// ABOUTME: Components module exports
|
|
2
|
+
// ABOUTME: Re-exports all React components for job UI
|
|
3
|
+
export { JobProgress } from './JobProgress.js';
|
|
4
|
+
export { JobEventLog } from './JobEventLog.js';
|
|
5
|
+
export { JobStatusBadge } from './JobStatusBadge.js';
|
|
6
|
+
export { JobCard } from './JobCard.js';
|
|
7
|
+
export { JobList } from './JobList.js';
|
|
8
|
+
export { JobFilters } from './JobFilters.js';
|
|
9
|
+
export { ConnectionStatus } from './ConnectionStatus.js';
|
|
10
|
+
export { CreateJobForm } from './CreateJobForm.js';
|
|
11
|
+
export { Dashboard } from './Dashboard.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { useJobStream, type UseJobStreamOptions, type UseJobStreamResult } from './use-job-stream.js';
|
|
2
|
+
export { useJob, type UseJobResult, type FetchJobFn, type JobData } from './use-job.js';
|
|
3
|
+
export { useJobList, type UseJobListResult, type FetchJobsFn, type ListJobsOptions, type ListJobsResult } from './use-job-list.js';
|
|
4
|
+
export { useConnection, type UseConnectionOptions, type UseConnectionResult } from './use-connection.js';
|