@flanksource/clicky-ui 0.3.6 → 0.3.7
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/README.md +42 -0
- package/dist/components/DateField.d.ts +1 -1
- package/dist/components/DatePicker.d.ts +1 -1
- package/dist/components/DateTimePicker.d.ts +1 -1
- package/dist/components/FormLookupProvider.cjs +12 -0
- package/dist/components/FormLookupProvider.cjs.map +1 -0
- package/dist/components/FormLookupProvider.d.ts +7 -0
- package/dist/components/FormLookupProvider.d.ts.map +1 -0
- package/dist/components/FormLookupProvider.js +12 -0
- package/dist/components/FormLookupProvider.js.map +1 -0
- package/dist/components/JsonSchemaForm.cjs +2 -2
- package/dist/components/JsonSchemaForm.cjs.map +1 -1
- package/dist/components/JsonSchemaForm.js +1 -1
- package/dist/components/JsonSchemaForm.js.map +1 -1
- package/dist/components/ListMenu.cjs +145 -0
- package/dist/components/ListMenu.cjs.map +1 -0
- package/dist/components/ListMenu.d.ts +54 -0
- package/dist/components/ListMenu.d.ts.map +1 -0
- package/dist/components/ListMenu.js +145 -0
- package/dist/components/ListMenu.js.map +1 -0
- package/dist/components/MdxEditorField.cjs +128 -0
- package/dist/components/MdxEditorField.cjs.map +1 -0
- package/dist/components/MdxEditorField.d.ts +4 -0
- package/dist/components/MdxEditorField.d.ts.map +1 -0
- package/dist/components/MdxEditorField.js +106 -0
- package/dist/components/MdxEditorField.js.map +1 -0
- package/dist/components/MdxEditorToolbar.cjs +76 -0
- package/dist/components/MdxEditorToolbar.cjs.map +1 -0
- package/dist/components/MdxEditorToolbar.d.ts +8 -0
- package/dist/components/MdxEditorToolbar.d.ts.map +1 -0
- package/dist/components/MdxEditorToolbar.js +76 -0
- package/dist/components/MdxEditorToolbar.js.map +1 -0
- package/dist/components/button-variants.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/form-lookup-context.cjs +1 -8
- package/dist/components/form-lookup-context.cjs.map +1 -1
- package/dist/components/form-lookup-context.d.ts +1 -5
- package/dist/components/form-lookup-context.d.ts.map +1 -1
- package/dist/components/form-lookup-context.js +1 -8
- package/dist/components/form-lookup-context.js.map +1 -1
- package/dist/components/jotai-bindings-core.cjs +197 -0
- package/dist/components/jotai-bindings-core.cjs.map +1 -0
- package/dist/components/jotai-bindings-core.d.ts +45 -0
- package/dist/components/jotai-bindings-core.d.ts.map +1 -0
- package/dist/components/jotai-bindings-core.js +197 -0
- package/dist/components/jotai-bindings-core.js.map +1 -0
- package/dist/components/jotai-bindings.cjs +17 -0
- package/dist/components/jotai-bindings.cjs.map +1 -0
- package/dist/components/jotai-bindings.d.ts +4 -0
- package/dist/components/jotai-bindings.d.ts.map +1 -0
- package/dist/components/jotai-bindings.js +17 -0
- package/dist/components/jotai-bindings.js.map +1 -0
- package/dist/components/json-schema-form-fields.cjs +37 -0
- package/dist/components/json-schema-form-fields.cjs.map +1 -1
- package/dist/components/json-schema-form-fields.d.ts +6 -0
- package/dist/components/json-schema-form-fields.d.ts.map +1 -1
- package/dist/components/json-schema-form-fields.js +38 -1
- package/dist/components/json-schema-form-fields.js.map +1 -1
- package/dist/components/json-schema-form-render.cjs +3 -1
- package/dist/components/json-schema-form-render.cjs.map +1 -1
- package/dist/components/json-schema-form-render.d.ts.map +1 -1
- package/dist/components/json-schema-form-render.js +4 -2
- package/dist/components/json-schema-form-render.js.map +1 -1
- package/dist/components/json-schema-form-resolve.cjs +9 -0
- package/dist/components/json-schema-form-resolve.cjs.map +1 -1
- package/dist/components/json-schema-form-resolve.d.ts.map +1 -1
- package/dist/components/json-schema-form-resolve.js +9 -0
- package/dist/components/json-schema-form-resolve.js.map +1 -1
- package/dist/components/json-schema-form-types.d.ts +4 -1
- package/dist/components/json-schema-form-types.d.ts.map +1 -1
- package/dist/components/mdx-editor-field-plugins.cjs +124 -0
- package/dist/components/mdx-editor-field-plugins.cjs.map +1 -0
- package/dist/components/mdx-editor-field-plugins.d.ts +6 -0
- package/dist/components/mdx-editor-field-plugins.d.ts.map +1 -0
- package/dist/components/mdx-editor-field-plugins.js +124 -0
- package/dist/components/mdx-editor-field-plugins.js.map +1 -0
- package/dist/components/mdx-editor-options.d.ts +77 -0
- package/dist/components/mdx-editor-options.d.ts.map +1 -0
- package/dist/components/use-list-menu-selection.cjs +77 -0
- package/dist/components/use-list-menu-selection.cjs.map +1 -0
- package/dist/components/use-list-menu-selection.d.ts +40 -0
- package/dist/components/use-list-menu-selection.d.ts.map +1 -0
- package/dist/components/use-list-menu-selection.js +77 -0
- package/dist/components/use-list-menu-selection.js.map +1 -0
- package/dist/components.cjs +10 -1
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.ts +4 -1
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +10 -1
- package/dist/components.js.map +1 -1
- package/dist/data/MarkdownEditor.model.d.ts +1 -1
- package/dist/data/PromptBanner.cjs +199 -0
- package/dist/data/PromptBanner.cjs.map +1 -0
- package/dist/data/PromptBanner.d.ts +17 -0
- package/dist/data/PromptBanner.d.ts.map +1 -0
- package/dist/data/PromptBanner.js +199 -0
- package/dist/data/PromptBanner.js.map +1 -0
- package/dist/data/PromptBanner.model.cjs +132 -0
- package/dist/data/PromptBanner.model.cjs.map +1 -0
- package/dist/data/PromptBanner.model.d.ts +23 -0
- package/dist/data/PromptBanner.model.d.ts.map +1 -0
- package/dist/data/PromptBanner.model.js +132 -0
- package/dist/data/PromptBanner.model.js.map +1 -0
- package/dist/data/PromptDialog.cjs +43 -0
- package/dist/data/PromptDialog.cjs.map +1 -0
- package/dist/data/PromptDialog.d.ts +14 -0
- package/dist/data/PromptDialog.d.ts.map +1 -0
- package/dist/data/PromptDialog.js +43 -0
- package/dist/data/PromptDialog.js.map +1 -0
- package/dist/data/TaskManager.cjs +8 -1
- package/dist/data/TaskManager.cjs.map +1 -1
- package/dist/data/TaskManager.d.ts.map +1 -1
- package/dist/data/TaskManager.js +8 -1
- package/dist/data/TaskManager.js.map +1 -1
- package/dist/data/TaskProgress.cjs +15 -2
- package/dist/data/TaskProgress.cjs.map +1 -1
- package/dist/data/TaskProgress.d.ts +0 -10
- package/dist/data/TaskProgress.d.ts.map +1 -1
- package/dist/data/TaskProgress.js +15 -2
- package/dist/data/TaskProgress.js.map +1 -1
- package/dist/data/ai/ChatWindow.cjs +53 -9
- package/dist/data/ai/ChatWindow.cjs.map +1 -1
- package/dist/data/ai/ChatWindow.d.ts.map +1 -1
- package/dist/data/ai/ChatWindow.js +53 -9
- package/dist/data/ai/ChatWindow.js.map +1 -1
- package/dist/data/ai/ToolPreferences.cjs +232 -39
- package/dist/data/ai/ToolPreferences.cjs.map +1 -1
- package/dist/data/ai/ToolPreferences.d.ts +4 -7
- package/dist/data/ai/ToolPreferences.d.ts.map +1 -1
- package/dist/data/ai/ToolPreferences.js +234 -41
- package/dist/data/ai/ToolPreferences.js.map +1 -1
- package/dist/data/chat/clickyOperationsToTools.cjs +89 -3
- package/dist/data/chat/clickyOperationsToTools.cjs.map +1 -1
- package/dist/data/chat/clickyOperationsToTools.d.ts +1 -1
- package/dist/data/chat/clickyOperationsToTools.d.ts.map +1 -1
- package/dist/data/chat/clickyOperationsToTools.js +89 -3
- package/dist/data/chat/clickyOperationsToTools.js.map +1 -1
- package/dist/data/chat/types.cjs.map +1 -1
- package/dist/data/chat/types.d.ts +7 -1
- package/dist/data/chat/types.d.ts.map +1 -1
- package/dist/data/chat/types.js.map +1 -1
- package/dist/data/task-status.cjs +19 -12
- package/dist/data/task-status.cjs.map +1 -1
- package/dist/data/task-status.d.ts +2 -1
- package/dist/data/task-status.d.ts.map +1 -1
- package/dist/data/task-status.js +19 -12
- package/dist/data/task-status.js.map +1 -1
- package/dist/data/test-runner/TestRunner.fixtures.d.ts +11 -4
- package/dist/data/test-runner/TestRunner.fixtures.d.ts.map +1 -1
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +7 -0
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +3 -0
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +7 -0
- package/dist/data.js.map +1 -1
- package/dist/hooks/use-prompts.cjs +83 -0
- package/dist/hooks/use-prompts.cjs.map +1 -0
- package/dist/hooks/use-prompts.d.ts +43 -0
- package/dist/hooks/use-prompts.d.ts.map +1 -0
- package/dist/hooks/use-prompts.js +83 -0
- package/dist/hooks/use-prompts.js.map +1 -0
- package/dist/hooks.cjs +3 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +1 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +3 -0
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +17 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/jotai.cjs +9 -0
- package/dist/jotai.cjs.map +1 -0
- package/dist/jotai.d.ts +4 -0
- package/dist/jotai.d.ts.map +1 -0
- package/dist/jotai.js +9 -0
- package/dist/jotai.js.map +1 -0
- package/dist/lib/utils.cjs +18 -1
- package/dist/lib/utils.cjs.map +1 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +18 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/mdx-editor.cjs +5 -0
- package/dist/mdx-editor.cjs.map +1 -0
- package/dist/mdx-editor.css +2 -0
- package/dist/mdx-editor.d.ts +2 -0
- package/dist/mdx-editor.d.ts.map +1 -0
- package/dist/mdx-editor.js +5 -0
- package/dist/mdx-editor.js.map +1 -0
- package/dist/rpc/apiClient.cjs +1 -1
- package/dist/rpc/apiClient.cjs.map +1 -1
- package/dist/rpc/apiClient.js +1 -1
- package/dist/rpc/apiClient.js.map +1 -1
- package/dist/rpc/surfaceIconMap.cjs +12 -1
- package/dist/rpc/surfaceIconMap.cjs.map +1 -1
- package/dist/rpc/surfaceIconMap.d.ts.map +1 -1
- package/dist/rpc/surfaceIconMap.js +12 -1
- package/dist/rpc/surfaceIconMap.js.map +1 -1
- package/dist/rpc/types.cjs.map +1 -1
- package/dist/rpc/types.d.ts +1 -0
- package/dist/rpc/types.d.ts.map +1 -1
- package/dist/rpc/types.js.map +1 -1
- package/dist/styles.css +1 -1
- package/oxlint-plugins/README.md +148 -0
- package/oxlint-plugins/clicky-ui-no-adhoc-overlay.js +88 -0
- package/oxlint-plugins/clicky-ui-prefer-components.js +46 -0
- package/oxlint-plugins/clicky-ui-prefer-icons.js +121 -0
- package/oxlint-plugins/clicky-ui-prefer-tailwind.js +98 -0
- package/oxlint-plugins/clicky-ui-prefer-theme.js +134 -0
- package/oxlint-plugins/clicky-ui-shared.js +132 -0
- package/oxlint-plugins/clicky-ui.js +34 -0
- package/oxlint-plugins/no-iconify-names.js +37 -0
- package/package.json +21 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const ACTION_FIELD_PRIORITY = ["decision", "choice", "action", "value", "approve", "approved"];
|
|
4
|
+
const COMMENT_FIELD_PRIORITY = ["comment", "reason", "message", "note"];
|
|
5
|
+
const APPROVE_RE = /\b(approve|approved|allow|allowed|continue|yes|accept|accepted|proceed|run)\b/i;
|
|
6
|
+
const REJECT_RE = /\b(reject|rejected|deny|denied|cancel|cancelled|canceled|no|block|stop|decline|declined)\b/i;
|
|
7
|
+
function hasType(schema, type) {
|
|
8
|
+
if (!(schema == null ? void 0 : schema.type)) return false;
|
|
9
|
+
return Array.isArray(schema.type) ? schema.type.includes(type) : schema.type === type;
|
|
10
|
+
}
|
|
11
|
+
function sortedPropertyEntries(schema) {
|
|
12
|
+
const entries = Object.entries(schema.properties ?? {});
|
|
13
|
+
return entries.sort(([a], [b]) => {
|
|
14
|
+
const ia = ACTION_FIELD_PRIORITY.indexOf(a);
|
|
15
|
+
const ib = ACTION_FIELD_PRIORITY.indexOf(b);
|
|
16
|
+
if (ia === -1 && ib === -1) return 0;
|
|
17
|
+
if (ia === -1) return 1;
|
|
18
|
+
if (ib === -1) return -1;
|
|
19
|
+
return ia - ib;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function optionText(schema, value) {
|
|
23
|
+
var _a;
|
|
24
|
+
const key = String(value);
|
|
25
|
+
const label = (_a = schema["x-enum-labels"]) == null ? void 0 : _a[key];
|
|
26
|
+
return [key, label].filter(Boolean).join(" ");
|
|
27
|
+
}
|
|
28
|
+
function findCommentField(schema) {
|
|
29
|
+
const properties = schema.properties ?? {};
|
|
30
|
+
const required = new Set(schema.required ?? []);
|
|
31
|
+
for (const key of COMMENT_FIELD_PRIORITY) {
|
|
32
|
+
const property = properties[key];
|
|
33
|
+
if (!property || !hasType(property, "string") || property.enum) continue;
|
|
34
|
+
return {
|
|
35
|
+
commentField: key,
|
|
36
|
+
commentRequired: required.has(key),
|
|
37
|
+
commentLabel: property.title ?? "Comment"
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return { commentRequired: false };
|
|
41
|
+
}
|
|
42
|
+
function findEnumAction(schema) {
|
|
43
|
+
for (const [field, property] of sortedPropertyEntries(schema)) {
|
|
44
|
+
const values = property.enum ?? [];
|
|
45
|
+
if (values.length === 0) continue;
|
|
46
|
+
const approve = values.find((value) => APPROVE_RE.test(optionText(property, value)));
|
|
47
|
+
const reject = values.find((value) => REJECT_RE.test(optionText(property, value)));
|
|
48
|
+
if (approve === void 0 || reject === void 0) continue;
|
|
49
|
+
return {
|
|
50
|
+
field,
|
|
51
|
+
approveValue: approve,
|
|
52
|
+
rejectValue: reject,
|
|
53
|
+
...findCommentField(schema)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
function findBooleanAction(schema) {
|
|
59
|
+
var _a;
|
|
60
|
+
const properties = schema.properties ?? {};
|
|
61
|
+
const preferred = ["value", "approve", "approved", "confirm", "confirmed", "allowed"];
|
|
62
|
+
const field = preferred.find((key) => hasType(properties[key], "boolean")) ?? ((_a = Object.entries(properties).find(([, property]) => hasType(property, "boolean"))) == null ? void 0 : _a[0]);
|
|
63
|
+
if (!field) return null;
|
|
64
|
+
return {
|
|
65
|
+
field,
|
|
66
|
+
approveValue: true,
|
|
67
|
+
rejectValue: false,
|
|
68
|
+
...findCommentField(schema)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function analyzePromptInlineActions(prompt) {
|
|
72
|
+
const schema = prompt.schema;
|
|
73
|
+
if (!(schema == null ? void 0 : schema.properties)) return null;
|
|
74
|
+
return findEnumAction(schema) ?? findBooleanAction(schema);
|
|
75
|
+
}
|
|
76
|
+
function initialPromptComment(prompt, spec) {
|
|
77
|
+
var _a;
|
|
78
|
+
if (!(spec == null ? void 0 : spec.commentField)) return "";
|
|
79
|
+
const value = (_a = prompt.value) == null ? void 0 : _a[spec.commentField];
|
|
80
|
+
return typeof value === "string" ? value : "";
|
|
81
|
+
}
|
|
82
|
+
function buildPromptInlineValues(prompt, spec, decision, comment) {
|
|
83
|
+
const values = { ...prompt.value };
|
|
84
|
+
values[spec.field] = decision === "approve" ? spec.approveValue : spec.rejectValue;
|
|
85
|
+
if (spec.commentField) {
|
|
86
|
+
const trimmed = comment.trim();
|
|
87
|
+
if (trimmed || spec.commentRequired) {
|
|
88
|
+
values[spec.commentField] = trimmed;
|
|
89
|
+
} else {
|
|
90
|
+
delete values[spec.commentField];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return values;
|
|
94
|
+
}
|
|
95
|
+
function summarizePrompts(prompts) {
|
|
96
|
+
return prompts.reduce(
|
|
97
|
+
(acc, prompt) => {
|
|
98
|
+
acc.total += 1;
|
|
99
|
+
if (prompt.state === "pending") acc.pending += 1;
|
|
100
|
+
else if (prompt.state === "answered") acc.answered += 1;
|
|
101
|
+
else if (prompt.state === "cancelled") acc.cancelled += 1;
|
|
102
|
+
else if (prompt.state === "expired") acc.expired += 1;
|
|
103
|
+
return acc;
|
|
104
|
+
},
|
|
105
|
+
{ total: 0, pending: 0, answered: 0, cancelled: 0, expired: 0 }
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
function summarizePromptAnswer(prompt) {
|
|
109
|
+
if (prompt.cancelled || prompt.state === "cancelled") return "Cancelled";
|
|
110
|
+
if (prompt.state === "expired") return "Expired";
|
|
111
|
+
if (prompt.state === "pending") return prompt.kind ? `Pending ${prompt.kind}` : "Pending";
|
|
112
|
+
const values = prompt.value ?? {};
|
|
113
|
+
const spec = analyzePromptInlineActions(prompt);
|
|
114
|
+
const parts = [];
|
|
115
|
+
if (spec && spec.field in values) {
|
|
116
|
+
if (Object.is(values[spec.field], spec.approveValue)) parts.push("Approved");
|
|
117
|
+
else if (Object.is(values[spec.field], spec.rejectValue)) parts.push("Rejected");
|
|
118
|
+
}
|
|
119
|
+
if (spec == null ? void 0 : spec.commentField) {
|
|
120
|
+
const comment = values[spec.commentField];
|
|
121
|
+
if (typeof comment === "string" && comment) parts.push(comment);
|
|
122
|
+
}
|
|
123
|
+
if (parts.length > 0) return parts.join(" - ");
|
|
124
|
+
const primitive = Object.entries(values).filter(([, value]) => ["string", "number", "boolean"].includes(typeof value)).slice(0, 2).map(([key, value]) => `${key}: ${String(value)}`);
|
|
125
|
+
return primitive.join(" - ") || prompt.state;
|
|
126
|
+
}
|
|
127
|
+
exports.analyzePromptInlineActions = analyzePromptInlineActions;
|
|
128
|
+
exports.buildPromptInlineValues = buildPromptInlineValues;
|
|
129
|
+
exports.initialPromptComment = initialPromptComment;
|
|
130
|
+
exports.summarizePromptAnswer = summarizePromptAnswer;
|
|
131
|
+
exports.summarizePrompts = summarizePrompts;
|
|
132
|
+
//# sourceMappingURL=PromptBanner.model.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptBanner.model.cjs","sources":["../../src/data/PromptBanner.model.ts"],"sourcesContent":["import type { JsonSchemaObject, JsonSchemaProperty } from \"../components/json-schema-form-types\";\nimport type { PromptSnapshot } from \"../hooks/use-prompts\";\n\nexport type PromptInlineDecision = \"approve\" | \"reject\";\n\nexport interface PromptInlineActionSpec {\n field: string;\n approveValue: unknown;\n rejectValue: unknown;\n commentField?: string;\n commentRequired: boolean;\n commentLabel?: string;\n}\n\nexport interface PromptSummary {\n total: number;\n pending: number;\n answered: number;\n cancelled: number;\n expired: number;\n}\n\nconst ACTION_FIELD_PRIORITY = [\"decision\", \"choice\", \"action\", \"value\", \"approve\", \"approved\"];\nconst COMMENT_FIELD_PRIORITY = [\"comment\", \"reason\", \"message\", \"note\"];\n\nconst APPROVE_RE = /\\b(approve|approved|allow|allowed|continue|yes|accept|accepted|proceed|run)\\b/i;\nconst REJECT_RE = /\\b(reject|rejected|deny|denied|cancel|cancelled|canceled|no|block|stop|decline|declined)\\b/i;\n\nfunction hasType(schema: JsonSchemaProperty | undefined, type: string): boolean {\n if (!schema?.type) return false;\n return Array.isArray(schema.type) ? schema.type.includes(type as never) : schema.type === type;\n}\n\nfunction sortedPropertyEntries(schema: JsonSchemaObject): [string, JsonSchemaProperty][] {\n const entries = Object.entries(schema.properties ?? {});\n return entries.sort(([a], [b]) => {\n const ia = ACTION_FIELD_PRIORITY.indexOf(a);\n const ib = ACTION_FIELD_PRIORITY.indexOf(b);\n if (ia === -1 && ib === -1) return 0;\n if (ia === -1) return 1;\n if (ib === -1) return -1;\n return ia - ib;\n });\n}\n\nfunction optionText(schema: JsonSchemaProperty, value: unknown): string {\n const key = String(value);\n const label = schema[\"x-enum-labels\"]?.[key];\n return [key, label].filter(Boolean).join(\" \");\n}\n\nfunction findCommentField(schema: JsonSchemaObject): Pick<\n PromptInlineActionSpec,\n \"commentField\" | \"commentRequired\" | \"commentLabel\"\n> {\n const properties = schema.properties ?? {};\n const required = new Set(schema.required ?? []);\n for (const key of COMMENT_FIELD_PRIORITY) {\n const property = properties[key];\n if (!property || !hasType(property, \"string\") || property.enum) continue;\n return {\n commentField: key,\n commentRequired: required.has(key),\n commentLabel: property.title ?? \"Comment\",\n };\n }\n return { commentRequired: false };\n}\n\nfunction findEnumAction(schema: JsonSchemaObject): PromptInlineActionSpec | null {\n for (const [field, property] of sortedPropertyEntries(schema)) {\n const values = property.enum ?? [];\n if (values.length === 0) continue;\n\n const approve = values.find((value) => APPROVE_RE.test(optionText(property, value)));\n const reject = values.find((value) => REJECT_RE.test(optionText(property, value)));\n if (approve === undefined || reject === undefined) continue;\n\n return {\n field,\n approveValue: approve,\n rejectValue: reject,\n ...findCommentField(schema),\n };\n }\n return null;\n}\n\nfunction findBooleanAction(schema: JsonSchemaObject): PromptInlineActionSpec | null {\n const properties = schema.properties ?? {};\n const preferred = [\"value\", \"approve\", \"approved\", \"confirm\", \"confirmed\", \"allowed\"];\n const field =\n preferred.find((key) => hasType(properties[key], \"boolean\")) ??\n Object.entries(properties).find(([, property]) => hasType(property, \"boolean\"))?.[0];\n\n if (!field) return null;\n return {\n field,\n approveValue: true,\n rejectValue: false,\n ...findCommentField(schema),\n };\n}\n\nexport function analyzePromptInlineActions(prompt: PromptSnapshot): PromptInlineActionSpec | null {\n const schema = prompt.schema;\n if (!schema?.properties) return null;\n return findEnumAction(schema) ?? findBooleanAction(schema);\n}\n\nexport function initialPromptComment(prompt: PromptSnapshot, spec: PromptInlineActionSpec | null): string {\n if (!spec?.commentField) return \"\";\n const value = prompt.value?.[spec.commentField];\n return typeof value === \"string\" ? value : \"\";\n}\n\nexport function buildPromptInlineValues(\n prompt: PromptSnapshot,\n spec: PromptInlineActionSpec,\n decision: PromptInlineDecision,\n comment: string,\n): Record<string, unknown> {\n const values: Record<string, unknown> = { ...prompt.value };\n values[spec.field] = decision === \"approve\" ? spec.approveValue : spec.rejectValue;\n\n if (spec.commentField) {\n const trimmed = comment.trim();\n if (trimmed || spec.commentRequired) {\n values[spec.commentField] = trimmed;\n } else {\n delete values[spec.commentField];\n }\n }\n\n return values;\n}\n\nexport function summarizePrompts(prompts: PromptSnapshot[]): PromptSummary {\n return prompts.reduce<PromptSummary>(\n (acc, prompt) => {\n acc.total += 1;\n if (prompt.state === \"pending\") acc.pending += 1;\n else if (prompt.state === \"answered\") acc.answered += 1;\n else if (prompt.state === \"cancelled\") acc.cancelled += 1;\n else if (prompt.state === \"expired\") acc.expired += 1;\n return acc;\n },\n { total: 0, pending: 0, answered: 0, cancelled: 0, expired: 0 },\n );\n}\n\nexport function summarizePromptAnswer(prompt: PromptSnapshot): string {\n if (prompt.cancelled || prompt.state === \"cancelled\") return \"Cancelled\";\n if (prompt.state === \"expired\") return \"Expired\";\n if (prompt.state === \"pending\") return prompt.kind ? `Pending ${prompt.kind}` : \"Pending\";\n\n const values = prompt.value ?? {};\n const spec = analyzePromptInlineActions(prompt);\n const parts: string[] = [];\n if (spec && spec.field in values) {\n if (Object.is(values[spec.field], spec.approveValue)) parts.push(\"Approved\");\n else if (Object.is(values[spec.field], spec.rejectValue)) parts.push(\"Rejected\");\n }\n if (spec?.commentField) {\n const comment = values[spec.commentField];\n if (typeof comment === \"string\" && comment) parts.push(comment);\n }\n if (parts.length > 0) return parts.join(\" - \");\n\n const primitive = Object.entries(values)\n .filter(([, value]) => [\"string\", \"number\", \"boolean\"].includes(typeof value))\n .slice(0, 2)\n .map(([key, value]) => `${key}: ${String(value)}`);\n return primitive.join(\" - \") || prompt.state;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PromptSnapshot } from '../hooks/use-prompts';
|
|
2
|
+
export type PromptInlineDecision = "approve" | "reject";
|
|
3
|
+
export interface PromptInlineActionSpec {
|
|
4
|
+
field: string;
|
|
5
|
+
approveValue: unknown;
|
|
6
|
+
rejectValue: unknown;
|
|
7
|
+
commentField?: string;
|
|
8
|
+
commentRequired: boolean;
|
|
9
|
+
commentLabel?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface PromptSummary {
|
|
12
|
+
total: number;
|
|
13
|
+
pending: number;
|
|
14
|
+
answered: number;
|
|
15
|
+
cancelled: number;
|
|
16
|
+
expired: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function analyzePromptInlineActions(prompt: PromptSnapshot): PromptInlineActionSpec | null;
|
|
19
|
+
export declare function initialPromptComment(prompt: PromptSnapshot, spec: PromptInlineActionSpec | null): string;
|
|
20
|
+
export declare function buildPromptInlineValues(prompt: PromptSnapshot, spec: PromptInlineActionSpec, decision: PromptInlineDecision, comment: string): Record<string, unknown>;
|
|
21
|
+
export declare function summarizePrompts(prompts: PromptSnapshot[]): PromptSummary;
|
|
22
|
+
export declare function summarizePromptAnswer(prompt: PromptSnapshot): string;
|
|
23
|
+
//# sourceMappingURL=PromptBanner.model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptBanner.model.d.ts","sourceRoot":"","sources":["../../src/data/PromptBanner.model.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAExD,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAoFD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,cAAc,GAAG,sBAAsB,GAAG,IAAI,CAIhG;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,sBAAsB,GAAG,IAAI,GAAG,MAAM,CAIxG;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,sBAAsB,EAC5B,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,EAAE,MAAM,GACd,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAczB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,aAAa,CAYzE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAuBpE"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
const ACTION_FIELD_PRIORITY = ["decision", "choice", "action", "value", "approve", "approved"];
|
|
2
|
+
const COMMENT_FIELD_PRIORITY = ["comment", "reason", "message", "note"];
|
|
3
|
+
const APPROVE_RE = /\b(approve|approved|allow|allowed|continue|yes|accept|accepted|proceed|run)\b/i;
|
|
4
|
+
const REJECT_RE = /\b(reject|rejected|deny|denied|cancel|cancelled|canceled|no|block|stop|decline|declined)\b/i;
|
|
5
|
+
function hasType(schema, type) {
|
|
6
|
+
if (!(schema == null ? void 0 : schema.type)) return false;
|
|
7
|
+
return Array.isArray(schema.type) ? schema.type.includes(type) : schema.type === type;
|
|
8
|
+
}
|
|
9
|
+
function sortedPropertyEntries(schema) {
|
|
10
|
+
const entries = Object.entries(schema.properties ?? {});
|
|
11
|
+
return entries.sort(([a], [b]) => {
|
|
12
|
+
const ia = ACTION_FIELD_PRIORITY.indexOf(a);
|
|
13
|
+
const ib = ACTION_FIELD_PRIORITY.indexOf(b);
|
|
14
|
+
if (ia === -1 && ib === -1) return 0;
|
|
15
|
+
if (ia === -1) return 1;
|
|
16
|
+
if (ib === -1) return -1;
|
|
17
|
+
return ia - ib;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function optionText(schema, value) {
|
|
21
|
+
var _a;
|
|
22
|
+
const key = String(value);
|
|
23
|
+
const label = (_a = schema["x-enum-labels"]) == null ? void 0 : _a[key];
|
|
24
|
+
return [key, label].filter(Boolean).join(" ");
|
|
25
|
+
}
|
|
26
|
+
function findCommentField(schema) {
|
|
27
|
+
const properties = schema.properties ?? {};
|
|
28
|
+
const required = new Set(schema.required ?? []);
|
|
29
|
+
for (const key of COMMENT_FIELD_PRIORITY) {
|
|
30
|
+
const property = properties[key];
|
|
31
|
+
if (!property || !hasType(property, "string") || property.enum) continue;
|
|
32
|
+
return {
|
|
33
|
+
commentField: key,
|
|
34
|
+
commentRequired: required.has(key),
|
|
35
|
+
commentLabel: property.title ?? "Comment"
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return { commentRequired: false };
|
|
39
|
+
}
|
|
40
|
+
function findEnumAction(schema) {
|
|
41
|
+
for (const [field, property] of sortedPropertyEntries(schema)) {
|
|
42
|
+
const values = property.enum ?? [];
|
|
43
|
+
if (values.length === 0) continue;
|
|
44
|
+
const approve = values.find((value) => APPROVE_RE.test(optionText(property, value)));
|
|
45
|
+
const reject = values.find((value) => REJECT_RE.test(optionText(property, value)));
|
|
46
|
+
if (approve === void 0 || reject === void 0) continue;
|
|
47
|
+
return {
|
|
48
|
+
field,
|
|
49
|
+
approveValue: approve,
|
|
50
|
+
rejectValue: reject,
|
|
51
|
+
...findCommentField(schema)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function findBooleanAction(schema) {
|
|
57
|
+
var _a;
|
|
58
|
+
const properties = schema.properties ?? {};
|
|
59
|
+
const preferred = ["value", "approve", "approved", "confirm", "confirmed", "allowed"];
|
|
60
|
+
const field = preferred.find((key) => hasType(properties[key], "boolean")) ?? ((_a = Object.entries(properties).find(([, property]) => hasType(property, "boolean"))) == null ? void 0 : _a[0]);
|
|
61
|
+
if (!field) return null;
|
|
62
|
+
return {
|
|
63
|
+
field,
|
|
64
|
+
approveValue: true,
|
|
65
|
+
rejectValue: false,
|
|
66
|
+
...findCommentField(schema)
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function analyzePromptInlineActions(prompt) {
|
|
70
|
+
const schema = prompt.schema;
|
|
71
|
+
if (!(schema == null ? void 0 : schema.properties)) return null;
|
|
72
|
+
return findEnumAction(schema) ?? findBooleanAction(schema);
|
|
73
|
+
}
|
|
74
|
+
function initialPromptComment(prompt, spec) {
|
|
75
|
+
var _a;
|
|
76
|
+
if (!(spec == null ? void 0 : spec.commentField)) return "";
|
|
77
|
+
const value = (_a = prompt.value) == null ? void 0 : _a[spec.commentField];
|
|
78
|
+
return typeof value === "string" ? value : "";
|
|
79
|
+
}
|
|
80
|
+
function buildPromptInlineValues(prompt, spec, decision, comment) {
|
|
81
|
+
const values = { ...prompt.value };
|
|
82
|
+
values[spec.field] = decision === "approve" ? spec.approveValue : spec.rejectValue;
|
|
83
|
+
if (spec.commentField) {
|
|
84
|
+
const trimmed = comment.trim();
|
|
85
|
+
if (trimmed || spec.commentRequired) {
|
|
86
|
+
values[spec.commentField] = trimmed;
|
|
87
|
+
} else {
|
|
88
|
+
delete values[spec.commentField];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return values;
|
|
92
|
+
}
|
|
93
|
+
function summarizePrompts(prompts) {
|
|
94
|
+
return prompts.reduce(
|
|
95
|
+
(acc, prompt) => {
|
|
96
|
+
acc.total += 1;
|
|
97
|
+
if (prompt.state === "pending") acc.pending += 1;
|
|
98
|
+
else if (prompt.state === "answered") acc.answered += 1;
|
|
99
|
+
else if (prompt.state === "cancelled") acc.cancelled += 1;
|
|
100
|
+
else if (prompt.state === "expired") acc.expired += 1;
|
|
101
|
+
return acc;
|
|
102
|
+
},
|
|
103
|
+
{ total: 0, pending: 0, answered: 0, cancelled: 0, expired: 0 }
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
function summarizePromptAnswer(prompt) {
|
|
107
|
+
if (prompt.cancelled || prompt.state === "cancelled") return "Cancelled";
|
|
108
|
+
if (prompt.state === "expired") return "Expired";
|
|
109
|
+
if (prompt.state === "pending") return prompt.kind ? `Pending ${prompt.kind}` : "Pending";
|
|
110
|
+
const values = prompt.value ?? {};
|
|
111
|
+
const spec = analyzePromptInlineActions(prompt);
|
|
112
|
+
const parts = [];
|
|
113
|
+
if (spec && spec.field in values) {
|
|
114
|
+
if (Object.is(values[spec.field], spec.approveValue)) parts.push("Approved");
|
|
115
|
+
else if (Object.is(values[spec.field], spec.rejectValue)) parts.push("Rejected");
|
|
116
|
+
}
|
|
117
|
+
if (spec == null ? void 0 : spec.commentField) {
|
|
118
|
+
const comment = values[spec.commentField];
|
|
119
|
+
if (typeof comment === "string" && comment) parts.push(comment);
|
|
120
|
+
}
|
|
121
|
+
if (parts.length > 0) return parts.join(" - ");
|
|
122
|
+
const primitive = Object.entries(values).filter(([, value]) => ["string", "number", "boolean"].includes(typeof value)).slice(0, 2).map(([key, value]) => `${key}: ${String(value)}`);
|
|
123
|
+
return primitive.join(" - ") || prompt.state;
|
|
124
|
+
}
|
|
125
|
+
export {
|
|
126
|
+
analyzePromptInlineActions,
|
|
127
|
+
buildPromptInlineValues,
|
|
128
|
+
initialPromptComment,
|
|
129
|
+
summarizePromptAnswer,
|
|
130
|
+
summarizePrompts
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=PromptBanner.model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptBanner.model.js","sources":["../../src/data/PromptBanner.model.ts"],"sourcesContent":["import type { JsonSchemaObject, JsonSchemaProperty } from \"../components/json-schema-form-types\";\nimport type { PromptSnapshot } from \"../hooks/use-prompts\";\n\nexport type PromptInlineDecision = \"approve\" | \"reject\";\n\nexport interface PromptInlineActionSpec {\n field: string;\n approveValue: unknown;\n rejectValue: unknown;\n commentField?: string;\n commentRequired: boolean;\n commentLabel?: string;\n}\n\nexport interface PromptSummary {\n total: number;\n pending: number;\n answered: number;\n cancelled: number;\n expired: number;\n}\n\nconst ACTION_FIELD_PRIORITY = [\"decision\", \"choice\", \"action\", \"value\", \"approve\", \"approved\"];\nconst COMMENT_FIELD_PRIORITY = [\"comment\", \"reason\", \"message\", \"note\"];\n\nconst APPROVE_RE = /\\b(approve|approved|allow|allowed|continue|yes|accept|accepted|proceed|run)\\b/i;\nconst REJECT_RE = /\\b(reject|rejected|deny|denied|cancel|cancelled|canceled|no|block|stop|decline|declined)\\b/i;\n\nfunction hasType(schema: JsonSchemaProperty | undefined, type: string): boolean {\n if (!schema?.type) return false;\n return Array.isArray(schema.type) ? schema.type.includes(type as never) : schema.type === type;\n}\n\nfunction sortedPropertyEntries(schema: JsonSchemaObject): [string, JsonSchemaProperty][] {\n const entries = Object.entries(schema.properties ?? {});\n return entries.sort(([a], [b]) => {\n const ia = ACTION_FIELD_PRIORITY.indexOf(a);\n const ib = ACTION_FIELD_PRIORITY.indexOf(b);\n if (ia === -1 && ib === -1) return 0;\n if (ia === -1) return 1;\n if (ib === -1) return -1;\n return ia - ib;\n });\n}\n\nfunction optionText(schema: JsonSchemaProperty, value: unknown): string {\n const key = String(value);\n const label = schema[\"x-enum-labels\"]?.[key];\n return [key, label].filter(Boolean).join(\" \");\n}\n\nfunction findCommentField(schema: JsonSchemaObject): Pick<\n PromptInlineActionSpec,\n \"commentField\" | \"commentRequired\" | \"commentLabel\"\n> {\n const properties = schema.properties ?? {};\n const required = new Set(schema.required ?? []);\n for (const key of COMMENT_FIELD_PRIORITY) {\n const property = properties[key];\n if (!property || !hasType(property, \"string\") || property.enum) continue;\n return {\n commentField: key,\n commentRequired: required.has(key),\n commentLabel: property.title ?? \"Comment\",\n };\n }\n return { commentRequired: false };\n}\n\nfunction findEnumAction(schema: JsonSchemaObject): PromptInlineActionSpec | null {\n for (const [field, property] of sortedPropertyEntries(schema)) {\n const values = property.enum ?? [];\n if (values.length === 0) continue;\n\n const approve = values.find((value) => APPROVE_RE.test(optionText(property, value)));\n const reject = values.find((value) => REJECT_RE.test(optionText(property, value)));\n if (approve === undefined || reject === undefined) continue;\n\n return {\n field,\n approveValue: approve,\n rejectValue: reject,\n ...findCommentField(schema),\n };\n }\n return null;\n}\n\nfunction findBooleanAction(schema: JsonSchemaObject): PromptInlineActionSpec | null {\n const properties = schema.properties ?? {};\n const preferred = [\"value\", \"approve\", \"approved\", \"confirm\", \"confirmed\", \"allowed\"];\n const field =\n preferred.find((key) => hasType(properties[key], \"boolean\")) ??\n Object.entries(properties).find(([, property]) => hasType(property, \"boolean\"))?.[0];\n\n if (!field) return null;\n return {\n field,\n approveValue: true,\n rejectValue: false,\n ...findCommentField(schema),\n };\n}\n\nexport function analyzePromptInlineActions(prompt: PromptSnapshot): PromptInlineActionSpec | null {\n const schema = prompt.schema;\n if (!schema?.properties) return null;\n return findEnumAction(schema) ?? findBooleanAction(schema);\n}\n\nexport function initialPromptComment(prompt: PromptSnapshot, spec: PromptInlineActionSpec | null): string {\n if (!spec?.commentField) return \"\";\n const value = prompt.value?.[spec.commentField];\n return typeof value === \"string\" ? value : \"\";\n}\n\nexport function buildPromptInlineValues(\n prompt: PromptSnapshot,\n spec: PromptInlineActionSpec,\n decision: PromptInlineDecision,\n comment: string,\n): Record<string, unknown> {\n const values: Record<string, unknown> = { ...prompt.value };\n values[spec.field] = decision === \"approve\" ? spec.approveValue : spec.rejectValue;\n\n if (spec.commentField) {\n const trimmed = comment.trim();\n if (trimmed || spec.commentRequired) {\n values[spec.commentField] = trimmed;\n } else {\n delete values[spec.commentField];\n }\n }\n\n return values;\n}\n\nexport function summarizePrompts(prompts: PromptSnapshot[]): PromptSummary {\n return prompts.reduce<PromptSummary>(\n (acc, prompt) => {\n acc.total += 1;\n if (prompt.state === \"pending\") acc.pending += 1;\n else if (prompt.state === \"answered\") acc.answered += 1;\n else if (prompt.state === \"cancelled\") acc.cancelled += 1;\n else if (prompt.state === \"expired\") acc.expired += 1;\n return acc;\n },\n { total: 0, pending: 0, answered: 0, cancelled: 0, expired: 0 },\n );\n}\n\nexport function summarizePromptAnswer(prompt: PromptSnapshot): string {\n if (prompt.cancelled || prompt.state === \"cancelled\") return \"Cancelled\";\n if (prompt.state === \"expired\") return \"Expired\";\n if (prompt.state === \"pending\") return prompt.kind ? `Pending ${prompt.kind}` : \"Pending\";\n\n const values = prompt.value ?? {};\n const spec = analyzePromptInlineActions(prompt);\n const parts: string[] = [];\n if (spec && spec.field in values) {\n if (Object.is(values[spec.field], spec.approveValue)) parts.push(\"Approved\");\n else if (Object.is(values[spec.field], spec.rejectValue)) parts.push(\"Rejected\");\n }\n if (spec?.commentField) {\n const comment = values[spec.commentField];\n if (typeof comment === \"string\" && comment) parts.push(comment);\n }\n if (parts.length > 0) return parts.join(\" - \");\n\n const primitive = Object.entries(values)\n .filter(([, value]) => [\"string\", \"number\", \"boolean\"].includes(typeof value))\n .slice(0, 2)\n .map(([key, value]) => `${key}: ${String(value)}`);\n return primitive.join(\" - \") || prompt.state;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const react = require("react");
|
|
5
|
+
const button = require("../components/button.cjs");
|
|
6
|
+
const JsonSchemaForm = require("../components/JsonSchemaForm.cjs");
|
|
7
|
+
const Modal = require("../overlay/Modal.cjs");
|
|
8
|
+
const usePrompts = require("../hooks/use-prompts.cjs");
|
|
9
|
+
function PromptDialog({ prompt, basePath, open, onClose, onResolved }) {
|
|
10
|
+
const [value, setValue] = react.useState(() => ({ ...prompt.value }));
|
|
11
|
+
const [busy, setBusy] = react.useState(false);
|
|
12
|
+
const [error, setError] = react.useState(null);
|
|
13
|
+
const resolve = async (answer) => {
|
|
14
|
+
setBusy(true);
|
|
15
|
+
setError(null);
|
|
16
|
+
try {
|
|
17
|
+
await usePrompts.answerPrompt(basePath, prompt.id, answer);
|
|
18
|
+
onResolved == null ? void 0 : onResolved();
|
|
19
|
+
onClose();
|
|
20
|
+
} catch (e) {
|
|
21
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
22
|
+
} finally {
|
|
23
|
+
setBusy(false);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
27
|
+
Modal.Modal,
|
|
28
|
+
{
|
|
29
|
+
open,
|
|
30
|
+
onClose,
|
|
31
|
+
title: prompt.title,
|
|
32
|
+
subtitle: prompt.description,
|
|
33
|
+
footer: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-2", children: [
|
|
34
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-auto text-sm text-red-600", children: error }) : null,
|
|
35
|
+
/* @__PURE__ */ jsxRuntime.jsx(button.Button, { variant: "ghost", disabled: busy, onClick: () => void resolve({ cancelled: true }), children: "Cancel" }),
|
|
36
|
+
/* @__PURE__ */ jsxRuntime.jsx(button.Button, { disabled: busy, onClick: () => void resolve({ values: value }), children: "Submit" })
|
|
37
|
+
] }),
|
|
38
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(JsonSchemaForm.JsonSchemaForm, { schema: prompt.schema, value, onChange: setValue, idPrefix: `prompt-${prompt.id}` })
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
exports.PromptDialog = PromptDialog;
|
|
43
|
+
//# sourceMappingURL=PromptDialog.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptDialog.cjs","sources":["../../src/data/PromptDialog.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Button } from \"../components/button\";\nimport { JsonSchemaForm } from \"../components/JsonSchemaForm\";\nimport { Modal } from \"../overlay/Modal\";\nimport { answerPrompt, type PromptSnapshot } from \"../hooks/use-prompts\";\n\nexport interface PromptDialogProps {\n /** The pending prompt to answer. Its `schema` drives the rendered form. */\n prompt: PromptSnapshot;\n /** Base path the prompt API is mounted under, e.g. \"/api/todos\". */\n basePath: string;\n open: boolean;\n /** Closes the modal without answering (the prompt stays pending). */\n onClose: () => void;\n /** Called after the prompt is successfully answered or cancelled. */\n onResolved?: (() => void) | undefined;\n}\n\n// PromptDialog renders a pending prompt's JSON Schema via the generic\n// JsonSchemaForm inside a Modal and POSTs the answer back to the prompt manager.\n// It is the human side of the same mechanism an AI model elicits through.\nexport function PromptDialog({ prompt, basePath, open, onClose, onResolved }: PromptDialogProps) {\n const [value, setValue] = useState<Record<string, unknown>>(() => ({ ...prompt.value }));\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const resolve = async (answer: { values?: Record<string, unknown>; cancelled?: boolean }) => {\n setBusy(true);\n setError(null);\n try {\n await answerPrompt(basePath, prompt.id, answer);\n onResolved?.();\n onClose();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={prompt.title}\n subtitle={prompt.description}\n footer={\n <div className=\"flex items-center justify-end gap-2\">\n {error ? <span className=\"mr-auto text-sm text-red-600\">{error}</span> : null}\n <Button variant=\"ghost\" disabled={busy} onClick={() => void resolve({ cancelled: true })}>\n Cancel\n </Button>\n <Button disabled={busy} onClick={() => void resolve({ values: value })}>\n Submit\n </Button>\n </div>\n }\n >\n <JsonSchemaForm schema={prompt.schema} value={value} onChange={setValue} idPrefix={`prompt-${prompt.id}`} />\n </Modal>\n );\n}\n"],"names":["useState","answerPrompt","jsx","Modal","jsxs","Button","JsonSchemaForm"],"mappings":";;;;;;;;AAqBO,SAAS,aAAa,EAAE,QAAQ,UAAU,MAAM,SAAS,cAAiC;AAC/F,QAAM,CAAC,OAAO,QAAQ,IAAIA,MAAAA,SAAkC,OAAO,EAAE,GAAG,OAAO,MAAA,EAAQ;AACvF,QAAM,CAAC,MAAM,OAAO,IAAIA,MAAAA,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAIA,MAAAA,SAAwB,IAAI;AAEtD,QAAM,UAAU,OAAO,WAAsE;AAC3F,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,YAAMC,WAAAA,aAAa,UAAU,OAAO,IAAI,MAAM;AAC9C;AACA,cAAA;AAAA,IACF,SAAS,GAAG;AACV,eAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,IACrD,UAAA;AACE,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SACEC,2BAAAA;AAAAA,IAACC,MAAAA;AAAAA,IAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,OAAO,OAAO;AAAA,MACd,UAAU,OAAO;AAAA,MACjB,QACEC,2BAAAA,KAAC,OAAA,EAAI,WAAU,uCACZ,UAAA;AAAA,QAAA,QAAQF,2BAAAA,IAAC,QAAA,EAAK,WAAU,gCAAgC,iBAAM,IAAU;AAAA,QACzEA,2BAAAA,IAACG,OAAAA,QAAA,EAAO,SAAQ,SAAQ,UAAU,MAAM,SAAS,MAAM,KAAK,QAAQ,EAAE,WAAW,KAAA,CAAM,GAAG,UAAA,UAE1F;AAAA,QACAH,2BAAAA,IAACG,OAAAA,QAAA,EAAO,UAAU,MAAM,SAAS,MAAM,KAAK,QAAQ,EAAE,QAAQ,MAAA,CAAO,GAAG,UAAA,SAAA,CAExE;AAAA,MAAA,GACF;AAAA,MAGF,UAAAH,2BAAAA,IAACI,eAAAA,gBAAA,EAAe,QAAQ,OAAO,QAAQ,OAAc,UAAU,UAAU,UAAU,UAAU,OAAO,EAAE,GAAA,CAAI;AAAA,IAAA;AAAA,EAAA;AAGhH;;"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PromptSnapshot } from '../hooks/use-prompts';
|
|
2
|
+
export interface PromptDialogProps {
|
|
3
|
+
/** The pending prompt to answer. Its `schema` drives the rendered form. */
|
|
4
|
+
prompt: PromptSnapshot;
|
|
5
|
+
/** Base path the prompt API is mounted under, e.g. "/api/todos". */
|
|
6
|
+
basePath: string;
|
|
7
|
+
open: boolean;
|
|
8
|
+
/** Closes the modal without answering (the prompt stays pending). */
|
|
9
|
+
onClose: () => void;
|
|
10
|
+
/** Called after the prompt is successfully answered or cancelled. */
|
|
11
|
+
onResolved?: (() => void) | undefined;
|
|
12
|
+
}
|
|
13
|
+
export declare function PromptDialog({ prompt, basePath, open, onClose, onResolved }: PromptDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=PromptDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptDialog.d.ts","sourceRoot":"","sources":["../../src/data/PromptDialog.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEzE,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,MAAM,EAAE,cAAc,CAAC;IACvB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,qEAAqE;IACrE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,qEAAqE;IACrE,UAAU,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACvC;AAKD,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,iBAAiB,2CAwC9F"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Button } from "../components/button.js";
|
|
4
|
+
import { JsonSchemaForm } from "../components/JsonSchemaForm.js";
|
|
5
|
+
import { Modal } from "../overlay/Modal.js";
|
|
6
|
+
import { answerPrompt } from "../hooks/use-prompts.js";
|
|
7
|
+
function PromptDialog({ prompt, basePath, open, onClose, onResolved }) {
|
|
8
|
+
const [value, setValue] = useState(() => ({ ...prompt.value }));
|
|
9
|
+
const [busy, setBusy] = useState(false);
|
|
10
|
+
const [error, setError] = useState(null);
|
|
11
|
+
const resolve = async (answer) => {
|
|
12
|
+
setBusy(true);
|
|
13
|
+
setError(null);
|
|
14
|
+
try {
|
|
15
|
+
await answerPrompt(basePath, prompt.id, answer);
|
|
16
|
+
onResolved == null ? void 0 : onResolved();
|
|
17
|
+
onClose();
|
|
18
|
+
} catch (e) {
|
|
19
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
20
|
+
} finally {
|
|
21
|
+
setBusy(false);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return /* @__PURE__ */ jsx(
|
|
25
|
+
Modal,
|
|
26
|
+
{
|
|
27
|
+
open,
|
|
28
|
+
onClose,
|
|
29
|
+
title: prompt.title,
|
|
30
|
+
subtitle: prompt.description,
|
|
31
|
+
footer: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
|
|
32
|
+
error ? /* @__PURE__ */ jsx("span", { className: "mr-auto text-sm text-red-600", children: error }) : null,
|
|
33
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", disabled: busy, onClick: () => void resolve({ cancelled: true }), children: "Cancel" }),
|
|
34
|
+
/* @__PURE__ */ jsx(Button, { disabled: busy, onClick: () => void resolve({ values: value }), children: "Submit" })
|
|
35
|
+
] }),
|
|
36
|
+
children: /* @__PURE__ */ jsx(JsonSchemaForm, { schema: prompt.schema, value, onChange: setValue, idPrefix: `prompt-${prompt.id}` })
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
PromptDialog
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=PromptDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptDialog.js","sources":["../../src/data/PromptDialog.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Button } from \"../components/button\";\nimport { JsonSchemaForm } from \"../components/JsonSchemaForm\";\nimport { Modal } from \"../overlay/Modal\";\nimport { answerPrompt, type PromptSnapshot } from \"../hooks/use-prompts\";\n\nexport interface PromptDialogProps {\n /** The pending prompt to answer. Its `schema` drives the rendered form. */\n prompt: PromptSnapshot;\n /** Base path the prompt API is mounted under, e.g. \"/api/todos\". */\n basePath: string;\n open: boolean;\n /** Closes the modal without answering (the prompt stays pending). */\n onClose: () => void;\n /** Called after the prompt is successfully answered or cancelled. */\n onResolved?: (() => void) | undefined;\n}\n\n// PromptDialog renders a pending prompt's JSON Schema via the generic\n// JsonSchemaForm inside a Modal and POSTs the answer back to the prompt manager.\n// It is the human side of the same mechanism an AI model elicits through.\nexport function PromptDialog({ prompt, basePath, open, onClose, onResolved }: PromptDialogProps) {\n const [value, setValue] = useState<Record<string, unknown>>(() => ({ ...prompt.value }));\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const resolve = async (answer: { values?: Record<string, unknown>; cancelled?: boolean }) => {\n setBusy(true);\n setError(null);\n try {\n await answerPrompt(basePath, prompt.id, answer);\n onResolved?.();\n onClose();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={prompt.title}\n subtitle={prompt.description}\n footer={\n <div className=\"flex items-center justify-end gap-2\">\n {error ? <span className=\"mr-auto text-sm text-red-600\">{error}</span> : null}\n <Button variant=\"ghost\" disabled={busy} onClick={() => void resolve({ cancelled: true })}>\n Cancel\n </Button>\n <Button disabled={busy} onClick={() => void resolve({ values: value })}>\n Submit\n </Button>\n </div>\n }\n >\n <JsonSchemaForm schema={prompt.schema} value={value} onChange={setValue} idPrefix={`prompt-${prompt.id}`} />\n </Modal>\n );\n}\n"],"names":[],"mappings":";;;;;;AAqBO,SAAS,aAAa,EAAE,QAAQ,UAAU,MAAM,SAAS,cAAiC;AAC/F,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAkC,OAAO,EAAE,GAAG,OAAO,MAAA,EAAQ;AACvF,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AAEtD,QAAM,UAAU,OAAO,WAAsE;AAC3F,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,YAAM,aAAa,UAAU,OAAO,IAAI,MAAM;AAC9C;AACA,cAAA;AAAA,IACF,SAAS,GAAG;AACV,eAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,IACrD,UAAA;AACE,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,OAAO,OAAO;AAAA,MACd,UAAU,OAAO;AAAA,MACjB,QACE,qBAAC,OAAA,EAAI,WAAU,uCACZ,UAAA;AAAA,QAAA,QAAQ,oBAAC,QAAA,EAAK,WAAU,gCAAgC,iBAAM,IAAU;AAAA,QACzE,oBAAC,QAAA,EAAO,SAAQ,SAAQ,UAAU,MAAM,SAAS,MAAM,KAAK,QAAQ,EAAE,WAAW,KAAA,CAAM,GAAG,UAAA,UAE1F;AAAA,QACA,oBAAC,QAAA,EAAO,UAAU,MAAM,SAAS,MAAM,KAAK,QAAQ,EAAE,QAAQ,MAAA,CAAO,GAAG,UAAA,SAAA,CAExE;AAAA,MAAA,GACF;AAAA,MAGF,UAAA,oBAAC,gBAAA,EAAe,QAAQ,OAAO,QAAQ,OAAc,UAAU,UAAU,UAAU,UAAU,OAAO,EAAE,GAAA,CAAI;AAAA,IAAA;AAAA,EAAA;AAGhH;"}
|
|
@@ -4,6 +4,7 @@ const jsxRuntime = require("react/jsx-runtime");
|
|
|
4
4
|
const react = require("react");
|
|
5
5
|
const utils = require("../lib/utils.cjs");
|
|
6
6
|
const useTaskRun = require("../hooks/use-task-run.cjs");
|
|
7
|
+
const Icon = require("./Icon.cjs");
|
|
7
8
|
const ProgressBar = require("./ProgressBar.cjs");
|
|
8
9
|
const Timestamp = require("./cells/Timestamp.cjs");
|
|
9
10
|
const TaskProgress = require("./TaskProgress.cjs");
|
|
@@ -99,7 +100,13 @@ function RunRow({
|
|
|
99
100
|
children: [
|
|
100
101
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
101
102
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
102
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
103
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
104
|
+
Icon.Icon,
|
|
105
|
+
{
|
|
106
|
+
icon: taskStatus.taskStatusIcon(run.status),
|
|
107
|
+
className: utils.cn(taskStatus.taskStatusColor(run.status), run.status === "running" && "animate-spin")
|
|
108
|
+
}
|
|
109
|
+
),
|
|
103
110
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: run.name }),
|
|
104
111
|
run.kind && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-muted px-1.5 py-0 text-[10px] text-muted-foreground", children: run.kind }),
|
|
105
112
|
isTerminal && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskManager.cjs","sources":["../../src/data/TaskManager.tsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useTaskRun, useTaskRuns } from \"../hooks/use-task-run\";\nimport { ProgressBar } from \"./ProgressBar\";\nimport { Timestamp } from \"./cells/Timestamp\";\nimport { TaskProgress } from \"./TaskProgress\";\nimport type { TaskRunMeta } from \"./TaskSnapshot\";\nimport { taskSegments, taskStatusBg, taskStatusColor, taskStatusIcon } from \"./task-status\";\n\n// TaskManager is the generic clicky-ui task-manager view: it lists every run\n// (TaskRunMeta) from GET {basePath}/tasks with kind/status filters, and expands\n// each row into a live <TaskProgress> for that run id. Fully generic — no\n// application concepts.\n\nexport interface TaskManagerProps {\n /** Base path of the clicky task API, e.g. \"/api/v1\". */\n basePath?: string;\n /** Restrict the listing to a single kind (also hides the kind filter). */\n kind?: string;\n pollMs?: number;\n className?: string;\n /**\n * Currently-selected (expanded) run id, e.g. driven from the URL. When set,\n * the matching run renders expanded and selection is controlled — otherwise\n * each row manages its own expand/collapse state.\n */\n selectedId?: string;\n /**\n * Called when a run row is toggled: the new selection id, or null when the\n * open row is collapsed. Pair with selectedId for URL-driven deep links.\n */\n onSelectRun?: (id: string | null) => void;\n}\n\nexport function TaskManager({\n basePath,\n kind,\n pollMs,\n className,\n selectedId,\n onSelectRun,\n}: TaskManagerProps) {\n const [kindFilter, setKindFilter] = useState<string>(kind ?? \"\");\n const [statusFilter, setStatusFilter] = useState<string>(\"\");\n const { runs, status } = useTaskRuns({\n basePath,\n kind: kind ?? (kindFilter || undefined),\n status: statusFilter || undefined,\n pollMs,\n });\n\n const kinds = useMemo(() => {\n const set = new Set<string>();\n for (const r of runs) if (r.kind) set.add(r.kind);\n return [...set].sort();\n }, [runs]);\n\n return (\n <div className={cn(\"space-y-3\", className)}>\n <div className=\"flex flex-wrap items-center gap-2\">\n {!kind && (\n <select\n className=\"rounded-md border bg-background px-2 py-1 text-xs\"\n value={kindFilter}\n onChange={(e) => setKindFilter(e.target.value)}\n >\n <option value=\"\">All kinds</option>\n {kinds.map((k) => (\n <option key={k} value={k}>\n {k}\n </option>\n ))}\n </select>\n )}\n <select\n className=\"rounded-md border bg-background px-2 py-1 text-xs\"\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value)}\n >\n <option value=\"\">Any status</option>\n <option value=\"running\">Running</option>\n <option value=\"pending\">Pending</option>\n <option value=\"success\">Success</option>\n <option value=\"failed\">Failed</option>\n <option value=\"warning\">Warning</option>\n </select>\n <span className=\"text-xs text-muted-foreground\">{status}</span>\n </div>\n\n {runs.length === 0 ? (\n <div className=\"rounded-lg border border-dashed p-6 text-center text-sm text-muted-foreground\">\n No background tasks.\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-lg border bg-card\">\n {runs.map((run) => (\n <RunRow\n key={run.id}\n run={run}\n basePath={basePath}\n pollMs={pollMs}\n selectedId={selectedId}\n onSelectRun={onSelectRun}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction RunRow({\n run,\n basePath,\n pollMs,\n selectedId,\n onSelectRun,\n}: {\n run: TaskRunMeta;\n basePath: string | undefined;\n pollMs: number | undefined;\n selectedId: string | undefined;\n onSelectRun: ((id: string | null) => void) | undefined;\n}) {\n const [localOpen, setLocalOpen] = useState(false);\n // Controlled by selectedId when a selection handler is wired; otherwise the\n // row owns its expand state (backward compatible for router-less consumers).\n const controlled = onSelectRun !== undefined;\n const open = controlled ? selectedId === run.id : localOpen;\n const toggle = () => {\n if (controlled) onSelectRun(open ? null : run.id);\n else setLocalOpen((v) => !v);\n };\n const isTerminal = run.status !== \"running\" && run.status !== \"pending\";\n\n return (\n <div className=\"border-b last:border-0\">\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-4 px-4 py-3 text-left hover:bg-muted/50\"\n onClick={toggle}\n >\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <iconify-icon icon={taskStatusIcon(run.status)} class={taskStatusColor(run.status)} />\n <span className=\"truncate font-medium\">{run.name}</span>\n {run.kind && (\n <span className=\"rounded-full bg-muted px-1.5 py-0 text-[10px] text-muted-foreground\">\n {run.kind}\n </span>\n )}\n {isTerminal && (\n <span\n className={cn(\n \"rounded-full px-2 py-0.5 text-xs\",\n taskStatusColor(run.status),\n taskStatusBg(run.status),\n )}\n >\n {run.status}\n </span>\n )}\n </div>\n <div className=\"mt-1 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-muted-foreground\">\n {run.startedAt && <Timestamp value={run.startedAt} format=\"relative\" />}\n <span>\n {run.completed + run.failed}/{run.total} done\n {run.failed > 0 ? `, ${run.failed} failed` : \"\"}\n </span>\n {Object.entries(run.labels ?? {}).map(([k, v]) => (\n <span key={k} className=\"font-mono\">\n {k}={v}\n </span>\n ))}\n </div>\n </div>\n <div className=\"w-40 shrink-0\">\n <ProgressBar\n segments={taskSegments({\n ok: run.completed,\n warn: 0,\n fail: run.failed,\n run: run.running,\n pending: Math.max(0, run.total - run.completed - run.failed - run.running),\n })}\n total={run.total || 1}\n height=\"h-1.5\"\n />\n </div>\n </button>\n {open && <ExpandedRun runId={run.id} basePath={basePath} pollMs={pollMs} />}\n </div>\n );\n}\n\nfunction ExpandedRun({\n runId,\n basePath,\n pollMs,\n}: {\n runId: string;\n basePath: string | undefined;\n pollMs: number | undefined;\n}) {\n const { snapshots } = useTaskRun({ id: runId, basePath, pollMs });\n return (\n <div className=\"border-t bg-muted/30 px-4 py-3\">\n <TaskProgress snapshots={snapshots} compact />\n </div>\n );\n}\n"],"names":["useState","useTaskRuns","useMemo","cn","jsxs","jsx","taskStatusIcon","taskStatusColor","taskStatusBg","Timestamp","ProgressBar","taskSegments","useTaskRun","TaskProgress"],"mappings":";;;;;;;;;;AAkCO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,CAAC,YAAY,aAAa,IAAIA,MAAAA,SAAiB,QAAQ,EAAE;AAC/D,QAAM,CAAC,cAAc,eAAe,IAAIA,MAAAA,SAAiB,EAAE;AAC3D,QAAM,EAAE,MAAM,OAAA,IAAWC,uBAAY;AAAA,IACnC;AAAA,IACA,MAAM,SAAS,cAAc;AAAA,IAC7B,QAAQ,gBAAgB;AAAA,IACxB;AAAA,EAAA,CACD;AAED,QAAM,QAAQC,MAAAA,QAAQ,MAAM;AAC1B,UAAM,0BAAU,IAAA;AAChB,eAAW,KAAK,KAAM,KAAI,EAAE,KAAM,KAAI,IAAI,EAAE,IAAI;AAChD,WAAO,CAAC,GAAG,GAAG,EAAE,KAAA;AAAA,EAClB,GAAG,CAAC,IAAI,CAAC;AAET,yCACG,OAAA,EAAI,WAAWC,MAAAA,GAAG,aAAa,SAAS,GACvC,UAAA;AAAA,IAAAC,2BAAAA,KAAC,OAAA,EAAI,WAAU,qCACZ,UAAA;AAAA,MAAA,CAAC,QACAA,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,cAAc,EAAE,OAAO,KAAK;AAAA,UAE7C,UAAA;AAAA,YAAAC,2BAAAA,IAAC,UAAA,EAAO,OAAM,IAAG,UAAA,aAAS;AAAA,YACzB,MAAM,IAAI,CAAC,MACVA,2BAAAA,IAAC,YAAe,OAAO,GACpB,UAAA,EAAA,GADU,CAEb,CACD;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAGLD,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,gBAAgB,EAAE,OAAO,KAAK;AAAA,UAE/C,UAAA;AAAA,YAAAC,2BAAAA,IAAC,UAAA,EAAO,OAAM,IAAG,UAAA,cAAU;AAAA,YAC3BA,2BAAAA,IAAC,UAAA,EAAO,OAAM,WAAU,UAAA,WAAO;AAAA,YAC/BA,2BAAAA,IAAC,UAAA,EAAO,OAAM,WAAU,UAAA,WAAO;AAAA,YAC/BA,2BAAAA,IAAC,UAAA,EAAO,OAAM,WAAU,UAAA,WAAO;AAAA,YAC/BA,2BAAAA,IAAC,UAAA,EAAO,OAAM,UAAS,UAAA,UAAM;AAAA,YAC7BA,2BAAAA,IAAC,UAAA,EAAO,OAAM,WAAU,UAAA,UAAA,CAAO;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAEjCA,2BAAAA,IAAC,QAAA,EAAK,WAAU,iCAAiC,UAAA,OAAA,CAAO;AAAA,IAAA,GAC1D;AAAA,IAEC,KAAK,WAAW,IACfA,2BAAAA,IAAC,OAAA,EAAI,WAAU,iFAAgF,UAAA,uBAAA,CAE/F,IAEAA,+BAAC,SAAI,WAAU,6CACZ,UAAA,KAAK,IAAI,CAAC,QACTA,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QAEC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MALK,IAAI;AAAA,IAAA,CAOZ,EAAA,CACH;AAAA,EAAA,GAEJ;AAEJ;AAEA,SAAS,OAAO;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,CAAC,WAAW,YAAY,IAAIL,MAAAA,SAAS,KAAK;AAGhD,QAAM,aAAa,gBAAgB;AACnC,QAAM,OAAO,aAAa,eAAe,IAAI,KAAK;AAClD,QAAM,SAAS,MAAM;AACnB,QAAI,WAAY,aAAY,OAAO,OAAO,IAAI,EAAE;AAAA,QAC3C,cAAa,CAAC,MAAM,CAAC,CAAC;AAAA,EAC7B;AACA,QAAM,aAAa,IAAI,WAAW,aAAa,IAAI,WAAW;AAE9D,SACEI,2BAAAA,KAAC,OAAA,EAAI,WAAU,0BACb,UAAA;AAAA,IAAAA,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS;AAAA,QAET,UAAA;AAAA,UAAAA,2BAAAA,KAAC,OAAA,EAAI,WAAU,kBACb,UAAA;AAAA,YAAAA,2BAAAA,KAAC,OAAA,EAAI,WAAU,2BACb,UAAA;AAAA,cAAAC,2BAAAA,IAAC,gBAAA,EAAa,MAAMC,WAAAA,eAAe,IAAI,MAAM,GAAG,OAAOC,WAAAA,gBAAgB,IAAI,MAAM,EAAA,CAAG;AAAA,cACpFF,2BAAAA,IAAC,QAAA,EAAK,WAAU,wBAAwB,cAAI,MAAK;AAAA,cAChD,IAAI,QACHA,2BAAAA,IAAC,UAAK,WAAU,uEACb,cAAI,MACP;AAAA,cAED,cACCA,2BAAAA;AAAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,WAAWF,MAAAA;AAAAA,oBACT;AAAA,oBACAI,WAAAA,gBAAgB,IAAI,MAAM;AAAA,oBAC1BC,WAAAA,aAAa,IAAI,MAAM;AAAA,kBAAA;AAAA,kBAGxB,UAAA,IAAI;AAAA,gBAAA;AAAA,cAAA;AAAA,YACP,GAEJ;AAAA,YACAJ,2BAAAA,KAAC,OAAA,EAAI,WAAU,oFACZ,UAAA;AAAA,cAAA,IAAI,aAAaC,2BAAAA,IAACI,qBAAA,EAAU,OAAO,IAAI,WAAW,QAAO,YAAW;AAAA,8CACpE,QAAA,EACE,UAAA;AAAA,gBAAA,IAAI,YAAY,IAAI;AAAA,gBAAO;AAAA,gBAAE,IAAI;AAAA,gBAAM;AAAA,gBACvC,IAAI,SAAS,IAAI,KAAK,IAAI,MAAM,YAAY;AAAA,cAAA,GAC/C;AAAA,cACC,OAAO,QAAQ,IAAI,UAAU,CAAA,CAAE,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAC1CL,2BAAAA,KAAC,QAAA,EAAa,WAAU,aACrB,UAAA;AAAA,gBAAA;AAAA,gBAAE;AAAA,gBAAE;AAAA,cAAA,EAAA,GADI,CAEX,CACD;AAAA,YAAA,EAAA,CACH;AAAA,UAAA,GACF;AAAA,UACAC,2BAAAA,IAAC,OAAA,EAAI,WAAU,iBACb,UAAAA,2BAAAA;AAAAA,YAACK,YAAAA;AAAAA,YAAA;AAAA,cACC,UAAUC,WAAAA,aAAa;AAAA,gBACrB,IAAI,IAAI;AAAA,gBACR,MAAM;AAAA,gBACN,MAAM,IAAI;AAAA,gBACV,KAAK,IAAI;AAAA,gBACT,SAAS,KAAK,IAAI,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,SAAS,IAAI,OAAO;AAAA,cAAA,CAC1E;AAAA,cACD,OAAO,IAAI,SAAS;AAAA,cACpB,QAAO;AAAA,YAAA;AAAA,UAAA,EACT,CACF;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAED,QAAQN,2BAAAA,IAAC,aAAA,EAAY,OAAO,IAAI,IAAI,UAAoB,OAAA,CAAgB;AAAA,EAAA,GAC3E;AAEJ;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,EAAE,cAAcO,sBAAW,EAAE,IAAI,OAAO,UAAU,QAAQ;AAChE,SACEP,2BAAAA,IAAC,SAAI,WAAU,kCACb,yCAACQ,aAAAA,cAAA,EAAa,WAAsB,SAAO,KAAA,CAAC,EAAA,CAC9C;AAEJ;;"}
|
|
1
|
+
{"version":3,"file":"TaskManager.cjs","sources":["../../src/data/TaskManager.tsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useTaskRun, useTaskRuns } from \"../hooks/use-task-run\";\nimport { Icon } from \"./Icon\";\nimport { ProgressBar } from \"./ProgressBar\";\nimport { Timestamp } from \"./cells/Timestamp\";\nimport { TaskProgress } from \"./TaskProgress\";\nimport type { TaskRunMeta } from \"./TaskSnapshot\";\nimport { taskSegments, taskStatusBg, taskStatusColor, taskStatusIcon } from \"./task-status\";\n\n// TaskManager is the generic clicky-ui task-manager view: it lists every run\n// (TaskRunMeta) from GET {basePath}/tasks with kind/status filters, and expands\n// each row into a live <TaskProgress> for that run id. Fully generic — no\n// application concepts.\n\nexport interface TaskManagerProps {\n /** Base path of the clicky task API, e.g. \"/api/v1\". */\n basePath?: string;\n /** Restrict the listing to a single kind (also hides the kind filter). */\n kind?: string;\n pollMs?: number;\n className?: string;\n /**\n * Currently-selected (expanded) run id, e.g. driven from the URL. When set,\n * the matching run renders expanded and selection is controlled — otherwise\n * each row manages its own expand/collapse state.\n */\n selectedId?: string;\n /**\n * Called when a run row is toggled: the new selection id, or null when the\n * open row is collapsed. Pair with selectedId for URL-driven deep links.\n */\n onSelectRun?: (id: string | null) => void;\n}\n\nexport function TaskManager({\n basePath,\n kind,\n pollMs,\n className,\n selectedId,\n onSelectRun,\n}: TaskManagerProps) {\n const [kindFilter, setKindFilter] = useState<string>(kind ?? \"\");\n const [statusFilter, setStatusFilter] = useState<string>(\"\");\n const { runs, status } = useTaskRuns({\n basePath,\n kind: kind ?? (kindFilter || undefined),\n status: statusFilter || undefined,\n pollMs,\n });\n\n const kinds = useMemo(() => {\n const set = new Set<string>();\n for (const r of runs) if (r.kind) set.add(r.kind);\n return [...set].sort();\n }, [runs]);\n\n return (\n <div className={cn(\"space-y-3\", className)}>\n <div className=\"flex flex-wrap items-center gap-2\">\n {!kind && (\n <select\n className=\"rounded-md border bg-background px-2 py-1 text-xs\"\n value={kindFilter}\n onChange={(e) => setKindFilter(e.target.value)}\n >\n <option value=\"\">All kinds</option>\n {kinds.map((k) => (\n <option key={k} value={k}>\n {k}\n </option>\n ))}\n </select>\n )}\n <select\n className=\"rounded-md border bg-background px-2 py-1 text-xs\"\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value)}\n >\n <option value=\"\">Any status</option>\n <option value=\"running\">Running</option>\n <option value=\"pending\">Pending</option>\n <option value=\"success\">Success</option>\n <option value=\"failed\">Failed</option>\n <option value=\"warning\">Warning</option>\n </select>\n <span className=\"text-xs text-muted-foreground\">{status}</span>\n </div>\n\n {runs.length === 0 ? (\n <div className=\"rounded-lg border border-dashed p-6 text-center text-sm text-muted-foreground\">\n No background tasks.\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-lg border bg-card\">\n {runs.map((run) => (\n <RunRow\n key={run.id}\n run={run}\n basePath={basePath}\n pollMs={pollMs}\n selectedId={selectedId}\n onSelectRun={onSelectRun}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction RunRow({\n run,\n basePath,\n pollMs,\n selectedId,\n onSelectRun,\n}: {\n run: TaskRunMeta;\n basePath: string | undefined;\n pollMs: number | undefined;\n selectedId: string | undefined;\n onSelectRun: ((id: string | null) => void) | undefined;\n}) {\n const [localOpen, setLocalOpen] = useState(false);\n // Controlled by selectedId when a selection handler is wired; otherwise the\n // row owns its expand state (backward compatible for router-less consumers).\n const controlled = onSelectRun !== undefined;\n const open = controlled ? selectedId === run.id : localOpen;\n const toggle = () => {\n if (controlled) onSelectRun(open ? null : run.id);\n else setLocalOpen((v) => !v);\n };\n const isTerminal = run.status !== \"running\" && run.status !== \"pending\";\n\n return (\n <div className=\"border-b last:border-0\">\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-4 px-4 py-3 text-left hover:bg-muted/50\"\n onClick={toggle}\n >\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <Icon\n icon={taskStatusIcon(run.status)}\n className={cn(taskStatusColor(run.status), run.status === \"running\" && \"animate-spin\")}\n />\n <span className=\"truncate font-medium\">{run.name}</span>\n {run.kind && (\n <span className=\"rounded-full bg-muted px-1.5 py-0 text-[10px] text-muted-foreground\">\n {run.kind}\n </span>\n )}\n {isTerminal && (\n <span\n className={cn(\n \"rounded-full px-2 py-0.5 text-xs\",\n taskStatusColor(run.status),\n taskStatusBg(run.status),\n )}\n >\n {run.status}\n </span>\n )}\n </div>\n <div className=\"mt-1 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-muted-foreground\">\n {run.startedAt && <Timestamp value={run.startedAt} format=\"relative\" />}\n <span>\n {run.completed + run.failed}/{run.total} done\n {run.failed > 0 ? `, ${run.failed} failed` : \"\"}\n </span>\n {Object.entries(run.labels ?? {}).map(([k, v]) => (\n <span key={k} className=\"font-mono\">\n {k}={v}\n </span>\n ))}\n </div>\n </div>\n <div className=\"w-40 shrink-0\">\n <ProgressBar\n segments={taskSegments({\n ok: run.completed,\n warn: 0,\n fail: run.failed,\n run: run.running,\n pending: Math.max(0, run.total - run.completed - run.failed - run.running),\n })}\n total={run.total || 1}\n height=\"h-1.5\"\n />\n </div>\n </button>\n {open && <ExpandedRun runId={run.id} basePath={basePath} pollMs={pollMs} />}\n </div>\n );\n}\n\nfunction ExpandedRun({\n runId,\n basePath,\n pollMs,\n}: {\n runId: string;\n basePath: string | undefined;\n pollMs: number | undefined;\n}) {\n const { snapshots } = useTaskRun({ id: runId, basePath, pollMs });\n return (\n <div className=\"border-t bg-muted/30 px-4 py-3\">\n <TaskProgress snapshots={snapshots} compact />\n </div>\n );\n}\n"],"names":["useState","useTaskRuns","useMemo","cn","jsxs","jsx","Icon","taskStatusIcon","taskStatusColor","taskStatusBg","Timestamp","ProgressBar","taskSegments","useTaskRun","TaskProgress"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskManager.d.ts","sourceRoot":"","sources":["../../src/data/TaskManager.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TaskManager.d.ts","sourceRoot":"","sources":["../../src/data/TaskManager.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC3C;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,SAAS,EACT,UAAU,EACV,WAAW,GACZ,EAAE,gBAAgB,2CAoElB"}
|
package/dist/data/TaskManager.js
CHANGED
|
@@ -2,6 +2,7 @@ import { jsxs, jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState, useMemo } from "react";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
4
|
import { useTaskRuns, useTaskRun } from "../hooks/use-task-run.js";
|
|
5
|
+
import { Icon } from "./Icon.js";
|
|
5
6
|
import { ProgressBar } from "./ProgressBar.js";
|
|
6
7
|
import { Timestamp } from "./cells/Timestamp.js";
|
|
7
8
|
import { TaskProgress } from "./TaskProgress.js";
|
|
@@ -97,7 +98,13 @@ function RunRow({
|
|
|
97
98
|
children: [
|
|
98
99
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
99
100
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
100
|
-
/* @__PURE__ */ jsx(
|
|
101
|
+
/* @__PURE__ */ jsx(
|
|
102
|
+
Icon,
|
|
103
|
+
{
|
|
104
|
+
icon: taskStatusIcon(run.status),
|
|
105
|
+
className: cn(taskStatusColor(run.status), run.status === "running" && "animate-spin")
|
|
106
|
+
}
|
|
107
|
+
),
|
|
101
108
|
/* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: run.name }),
|
|
102
109
|
run.kind && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-muted px-1.5 py-0 text-[10px] text-muted-foreground", children: run.kind }),
|
|
103
110
|
isTerminal && /* @__PURE__ */ jsx(
|