rowvia 0.3.0 → 0.3.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.
@@ -198,12 +198,16 @@ export interface FormPlacement {
198
198
  export interface FormGroupConfig {
199
199
  id: string;
200
200
  label: string;
201
- items: FormPlacement[];
201
+ items: FormLayoutItem[];
202
+ columns?: 1 | 2;
203
+ columnRatio?: [number, number];
204
+ span?: 1 | 2;
202
205
  visibleWhen?: FormCondition;
203
206
  }
204
- export type FormLayoutItem = FormPlacement | FormGroupConfig;
207
+ export type FormLayoutItem = FormPlacement | FormGroupConfig | FormBlockConfig;
205
208
  export interface FormBlockConfig {
206
209
  id: string;
210
+ span?: 1 | 2;
207
211
  kind: 'roles' | 'meetings' | 'approval' | 'votes' | 'custom';
208
212
  label?: string;
209
213
  visibleWhen?: FormCondition;
@@ -19,6 +19,8 @@ export * from './gantt';
19
19
  export * from './node-flow';
20
20
  export * from './personnel';
21
21
  export * from './work-items';
22
+ export { createWorkflowDetail } from './work-items/workflow-detail';
23
+ export type * from './work-items/workflow-detail-types';
22
24
  export { createControlRegistry, BaseFieldControl, sanitizeRichText } from './work-items/fields/registry';
23
25
  export { createWorkItemFormSurface, evalFormCondition, evalFormScope } from './forms/form-surface';
24
26
  export type { ComponentInteraction, InteractionOptions, InteractionSource } from './shared/interaction';
@@ -0,0 +1,44 @@
1
+ import type { WorkItem } from '../../contracts/work-item';
2
+ import type { FieldServices, FieldOption } from '../../fields/types';
3
+ export type DetailComment = Exclude<WorkItem['comments'][number], string> & {
4
+ authorId?: string;
5
+ replyTo?: string;
6
+ };
7
+ export interface DetailCommentSave {
8
+ action: 'create' | 'edit' | 'reply';
9
+ id?: string;
10
+ replyTo?: string;
11
+ html: string;
12
+ content: string;
13
+ }
14
+ export interface DetailCommentsPermissions {
15
+ create?: boolean;
16
+ reply?: boolean | ((comment: DetailComment) => boolean);
17
+ edit?: boolean | ((comment: DetailComment) => boolean);
18
+ }
19
+ export interface DetailCommentsOptions {
20
+ comments?: Array<string | DetailComment>;
21
+ data?: Array<string | DetailComment>;
22
+ author: string | {
23
+ id: string;
24
+ display: string;
25
+ };
26
+ permissions?: DetailCommentsPermissions;
27
+ people?: FieldOption[];
28
+ services?: Pick<FieldServices, 'searchOptions'>;
29
+ onSave?: (command: DetailCommentSave, signal: AbortSignal) => WorkItem['comments'] | Promise<WorkItem['comments']>;
30
+ onPublish?: (payload: DetailCommentSave, signal: AbortSignal) => boolean | Promise<boolean>;
31
+ onEdit?: (id: string, payload: DetailCommentSave, signal: AbortSignal) => boolean | Promise<boolean>;
32
+ hasMore?: boolean;
33
+ onLoadMore?: (signal: AbortSignal) => void | Promise<void>;
34
+ renderActions?: (container: HTMLElement, comment: DetailComment) => void | (() => void);
35
+ renderAttachments?: (container: HTMLElement, comment: DetailComment) => void | (() => void);
36
+ }
37
+ export declare function createDetailComments(initial: DetailCommentsOptions): {
38
+ element: HTMLElement;
39
+ composer: HTMLDivElement;
40
+ decorateTab: (surface: HTMLElement) => void;
41
+ update: (patch: Partial<Pick<DetailCommentsOptions, "comments" | "data" | "permissions" | "hasMore">>) => void;
42
+ deactivate: () => void;
43
+ destroy: () => void;
44
+ };
@@ -0,0 +1,38 @@
1
+ import type { WorkItem } from '../../contracts/work-item';
2
+ import { type HistoryQuery, type HistoryEntry, type HistoryModule } from './history-model';
3
+ export interface DetailHistoryPage {
4
+ rows: HistoryEntry[];
5
+ total?: number;
6
+ matching?: number;
7
+ nextCursor?: string | null;
8
+ previousCursor?: string | null;
9
+ }
10
+ export interface DetailHistoryQuery extends HistoryQuery {
11
+ cursor?: string;
12
+ }
13
+ export interface DetailHistoryOptions {
14
+ records?: WorkItem['history'];
15
+ rows?: HistoryEntry[];
16
+ query?: Partial<DetailHistoryQuery>;
17
+ nextCursor?: string | null;
18
+ previousCursor?: string | null;
19
+ actor?: string;
20
+ nodeFlow?: boolean;
21
+ mode?: 'server' | 'local';
22
+ page?: DetailHistoryPage;
23
+ modules?: HistoryModule[];
24
+ operators?: Array<{
25
+ id: string;
26
+ label: string;
27
+ }>;
28
+ onQuery?: (query: DetailHistoryQuery, signal: AbortSignal) => DetailHistoryPage | void | Promise<DetailHistoryPage | void>;
29
+ onLoadMore?: (cursor: string, query: DetailHistoryQuery, signal: AbortSignal) => DetailHistoryPage | void | Promise<DetailHistoryPage | void>;
30
+ renderDetail?: (container: HTMLElement, entry: HistoryEntry) => void | (() => void);
31
+ }
32
+ export declare function createDetailHistory(initial: DetailHistoryOptions): {
33
+ element: HTMLElement;
34
+ refresh: (loadMore?: boolean) => void;
35
+ deactivate: () => void;
36
+ update: (patch: Partial<Pick<DetailHistoryOptions, "records" | "rows" | "page" | "query" | "nextCursor" | "previousCursor" | "modules" | "operators">>) => void;
37
+ destroy: () => void;
38
+ };
@@ -0,0 +1,48 @@
1
+ import type { WorkItem } from '../../contracts/work-item';
2
+ export type HistoryEntry = Exclude<WorkItem['history'][number], string>;
3
+ export interface HistoryModule {
4
+ key: string;
5
+ label: string;
6
+ }
7
+ export interface HistoryQuery {
8
+ keyword: string;
9
+ keywordFilter: boolean;
10
+ operatorKinds: Set<string>;
11
+ operators: Set<string>;
12
+ modules: Set<string>;
13
+ start: string;
14
+ end: string;
15
+ page: number;
16
+ }
17
+ export declare const historyModules: HistoryModule[];
18
+ export declare function normalizeHistory(item: Pick<WorkItem, 'history'>, actor: string): HistoryEntry[];
19
+ /** The log endpoint already supplies localized display content; origin_content is not HTML. */
20
+ export declare function adaptOperationRecords(records: Array<{
21
+ id: string;
22
+ operator?: {
23
+ user_key: string;
24
+ name: string;
25
+ };
26
+ operator_type: number;
27
+ op_record_type_key: string;
28
+ op_record_type_name: string;
29
+ content: string;
30
+ created_at: number;
31
+ }>): HistoryEntry[];
32
+ export declare function queryHistory(logs: HistoryEntry[], query: HistoryQuery): {
33
+ rows: {
34
+ id?: string;
35
+ actor: string;
36
+ actorId?: string;
37
+ actorKind?: "user" | "computed" | "automation" | "system";
38
+ module: string;
39
+ moduleKey?: string;
40
+ detail: string;
41
+ createdAt: string;
42
+ }[];
43
+ total: number;
44
+ matching: number;
45
+ filteredTotal: number;
46
+ page: number;
47
+ pageCount: number;
48
+ };
@@ -1,4 +1,12 @@
1
1
  export type * from '../contracts/work-item';
2
+ export { createWorkflowDetail } from './workflow-detail';
3
+ export type * from './workflow-detail-types';
4
+ export { createDetailComments } from './detail/detail-comments';
5
+ export type { DetailComment, DetailCommentSave, DetailCommentsPermissions, DetailCommentsOptions } from './detail/detail-comments';
6
+ export { createDetailHistory } from './detail/detail-history';
7
+ export type { DetailHistoryPage, DetailHistoryQuery, DetailHistoryOptions } from './detail/detail-history';
8
+ export { historyModules, normalizeHistory, queryHistory, adaptOperationRecords } from './detail/history-model';
9
+ export type { HistoryEntry, HistoryModule, HistoryQuery } from './detail/history-model';
2
10
  export type { FormCondition, FormConditionOp, FormScope, FormSurfaceContext } from '../forms/form-conditions';
3
11
  export { emptyView, matches } from './model';
4
12
  export { createWorkItemTabs } from './tabs';
@@ -0,0 +1,51 @@
1
+ import type { FlowDefinition, FlowNode } from '../node-flow/types';
2
+ /** demand_fetch 的 modules / biz_data / ui_data 在 demo 中的轻量投影。
3
+ * 配置控制区域与字段,FlowNode 只提供实例值;不依赖 node-flow 组件。 */
4
+ export declare function projectWorkflowDetail(flow: FlowDefinition): {
5
+ controls: {
6
+ roles: {
7
+ id: string;
8
+ label: string;
9
+ color?: string;
10
+ nodeIds?: string[];
11
+ enabled?: boolean;
12
+ tooltip?: string;
13
+ }[];
14
+ switches: {
15
+ id: string;
16
+ label: string;
17
+ checked: boolean;
18
+ nodeIds?: string[];
19
+ }[];
20
+ };
21
+ graph: {
22
+ nodes: FlowNode[];
23
+ edges: {
24
+ from: string;
25
+ to: string;
26
+ }[];
27
+ };
28
+ nodeList: FlowNode[];
29
+ node: (node: FlowNode) => {
30
+ data: FlowNode;
31
+ form: import("..").FormItem[];
32
+ fields: {
33
+ key: "owner" | "schedule" | "estimate";
34
+ label: string;
35
+ }[];
36
+ sections: ("form" | "tasks")[];
37
+ completeLabel: string;
38
+ deletable: boolean;
39
+ };
40
+ };
41
+ /** 按实际依赖拓扑分列,不根据阶段名猜测连线。 */
42
+ export declare function layoutWorkflowGraph(graph: ReturnType<typeof projectWorkflowDetail>['graph']): {
43
+ nodes: {
44
+ node: FlowNode;
45
+ x: number;
46
+ y: number;
47
+ width: number;
48
+ }[];
49
+ paths: string[];
50
+ width: number;
51
+ };
@@ -0,0 +1,95 @@
1
+ import type { CustomButton, FlowDefinition, FlowNode, FormItem, NodeField, SubTask } from '../node-flow/types';
2
+ export type WorkflowDetailCommand = {
3
+ type: 'update-node';
4
+ nodeId: string;
5
+ patch: Partial<FlowNode>;
6
+ detail: string;
7
+ } | {
8
+ type: 'delete-node';
9
+ nodeId: string;
10
+ } | {
11
+ type: 'update-flow';
12
+ detail: NonNullable<FlowDefinition['detail']>;
13
+ } | {
14
+ type: 'action';
15
+ nodeId: string;
16
+ actionId: string;
17
+ };
18
+ export type WorkflowDetailPermission = 'edit' | 'complete' | 'delete' | 'create-task' | 'toggle-task' | 'configure' | 'action';
19
+ export interface WorkflowDetailRenderContext {
20
+ node: FlowNode;
21
+ surface: 'selected' | 'list';
22
+ readonly: boolean;
23
+ pending: boolean;
24
+ signal: AbortSignal;
25
+ context: WorkflowDetailContext;
26
+ can(permission: WorkflowDetailPermission, key?: string): boolean;
27
+ commit(patch: Partial<FlowNode>, detail?: string): Promise<boolean>;
28
+ action(actionId: string): Promise<boolean>;
29
+ }
30
+ export interface WorkflowDetailContext {
31
+ currentUser?: string;
32
+ people?: {
33
+ id: string;
34
+ name: string;
35
+ }[];
36
+ workItems?: {
37
+ id: string;
38
+ name: string;
39
+ }[];
40
+ }
41
+ export type WorkflowDetailResult = FlowDefinition | void | Promise<FlowDefinition | void>;
42
+ export interface WorkflowDetailCallbackContext {
43
+ flow: FlowDefinition;
44
+ signal: AbortSignal;
45
+ }
46
+ export interface WorkflowDetailOptions {
47
+ flow: FlowDefinition;
48
+ selectedNodeId?: string;
49
+ currentUser?: string;
50
+ workItems?: {
51
+ id: string;
52
+ name: string;
53
+ }[];
54
+ readonly?: boolean;
55
+ context?: WorkflowDetailContext;
56
+ can?: (permission: WorkflowDetailPermission, node?: FlowNode, key?: string) => boolean;
57
+ onChange?: (nodeId: string, patch: Partial<FlowNode>, detail: string, context: WorkflowDetailCallbackContext) => WorkflowDetailResult;
58
+ onComplete?: (nodeId: string, context: WorkflowDetailCallbackContext) => WorkflowDetailResult;
59
+ onAction?: (nodeId: string, actionId: string, context: WorkflowDetailCallbackContext) => WorkflowDetailResult;
60
+ onDelete?: (nodeId: string, context: WorkflowDetailCallbackContext) => WorkflowDetailResult;
61
+ onFlowChange?: (detail: NonNullable<FlowDefinition['detail']>, context: WorkflowDetailCallbackContext) => WorkflowDetailResult;
62
+ onCreateTask?: (nodeId: string, context: WorkflowDetailCallbackContext) => WorkflowDetailResult;
63
+ taskColumns?: (node: FlowNode) => {
64
+ key: string;
65
+ label: string;
66
+ }[];
67
+ renderTaskField?: (host: HTMLElement, task: SubTask, column: {
68
+ key: string;
69
+ label: string;
70
+ }, context: WorkflowDetailRenderContext) => void | (() => void);
71
+ onCommand?: (command: WorkflowDetailCommand, context: {
72
+ flow: FlowDefinition;
73
+ signal: AbortSignal;
74
+ }) => FlowDefinition | void | Promise<FlowDefinition | void>;
75
+ onError?: (error: unknown, command: WorkflowDetailCommand) => void;
76
+ onSelectNode?: (nodeId: string) => void;
77
+ renderField?: (container: HTMLElement, field: FormItem | NodeField, context: WorkflowDetailRenderContext) => void | (() => void);
78
+ renderSystemField?: (container: HTMLElement, field: {
79
+ key: 'owner' | 'schedule' | 'estimate';
80
+ label: string;
81
+ }, context: WorkflowDetailRenderContext) => void | (() => void);
82
+ renderActions?: (container: HTMLElement, buttons: CustomButton[], context: WorkflowDetailRenderContext) => void | (() => void);
83
+ renderNodeFields?: (node: FlowNode, host: HTMLElement, context: WorkflowDetailRenderContext) => void | (() => void);
84
+ renderNodeForm?: (node: FlowNode, host: HTMLElement, context: WorkflowDetailRenderContext) => void | (() => void);
85
+ }
86
+ export interface WorkflowDetailApi {
87
+ element: HTMLElement;
88
+ nodeListElement: HTMLElement;
89
+ renderNodeDetails(): HTMLElement;
90
+ setFlow(flow: FlowDefinition): void;
91
+ update(options: Partial<WorkflowDetailOptions>): void;
92
+ selectNode(nodeId: string): void;
93
+ getSelectedNode(): FlowNode | undefined;
94
+ destroy(): void;
95
+ }
@@ -0,0 +1,3 @@
1
+ import type { WorkflowDetailApi, WorkflowDetailOptions } from './workflow-detail-types';
2
+ export type * from './workflow-detail-types';
3
+ export declare function createWorkflowDetail(options: WorkflowDetailOptions): WorkflowDetailApi;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rowvia",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "零运行时依赖的 TypeScript 数据表格、甘特图与人员排期组件库",
5
5
  "type": "module",
6
6
  "scripts": {