zidane-ui 9.1.3 → 9.1.5
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/adapters/server-extensions-host.js +1 -1
- package/dist/adapters/server-host.js +2 -1
- package/dist/adapters/server-machines-host.js +1 -1
- package/dist/adapters/server-session-host.js +87 -13
- package/dist/adapters/server-settings-host.js +1 -1
- package/dist/appearance/AppearanceProvider.js +2 -2
- package/dist/appearance/headless/index.js +1 -1
- package/dist/approvals/headless/index.js +2 -2
- package/dist/chat/HostTranscript.d.ts +5 -1
- package/dist/chat/HostTranscript.js +16 -4
- package/dist/chat/RunEstimateChip.d.ts +5 -3
- package/dist/chat/RunEstimateChip.js +33 -3
- package/dist/chat/Transcript.js +1 -1
- package/dist/chat/composer/ComposerEditor.js +1 -1
- package/dist/chat/composer/ConversationBadges.js +16 -10
- package/dist/chat/composer/composer-bus.d.ts +2 -2
- package/dist/chat/composer/composer-bus.js +2 -2
- package/dist/chat/composer/use-composer-stores.js +1 -1
- package/dist/chat/composer/use-run-meter.js +1 -1
- package/dist/chat/headless/composer/conversation-badges.d.ts +8 -3
- package/dist/chat/headless/composer/conversation-badges.js +26 -11
- package/dist/chat/headless/composer/index.js +2 -2
- package/dist/chat/headless/composer/labels-chrome.d.ts +3 -1
- package/dist/chat/headless/composer/labels-chrome.js +3 -1
- package/dist/chat/headless/index.d.ts +5 -3
- package/dist/chat/headless/index.js +17 -15
- package/dist/chat/headless/labels.d.ts +54 -1
- package/dist/chat/headless/labels.js +62 -2
- package/dist/chat/headless/secrets.d.ts +32 -0
- package/dist/chat/headless/secrets.js +43 -0
- package/dist/chat/headless/session-list.d.ts +45 -0
- package/dist/chat/headless/sidebar/estimates.js +13 -1
- package/dist/chat/headless/sidebar/index.d.ts +2 -2
- package/dist/chat/headless/sidebar/index.js +1 -1
- package/dist/chat/headless/sidebar/labels.d.ts +50 -0
- package/dist/chat/headless/sidebar/labels.js +1 -0
- package/dist/chat/headless/sidebar/query.d.ts +2 -2
- package/dist/chat/headless/sidebar/query.js +6 -3
- package/dist/chat/headless/sidebar/types.d.ts +7 -1
- package/dist/chat/headless/sidebar/view.js +2 -0
- package/dist/chat/headless/transcript/auth-failure.d.ts +67 -0
- package/dist/chat/headless/transcript/auth-failure.js +87 -0
- package/dist/chat/headless/transcript/index.d.ts +2 -1
- package/dist/chat/headless/transcript/index.js +2 -1
- package/dist/chat/headless/transcript/nesting.d.ts +3 -3
- package/dist/chat/headless/transcript/nesting.js +12 -4
- package/dist/chat/index.d.ts +4 -2
- package/dist/chat/index.js +3 -1
- package/dist/chat/interactions/InboxPanel.d.ts +6 -2
- package/dist/chat/interactions/InboxPanel.js +82 -44
- package/dist/chat/interactions/PlanCard.d.ts +2 -2
- package/dist/chat/interactions/PlanCard.js +1 -1
- package/dist/chat/interactions/QuestionField.d.ts +8 -3
- package/dist/chat/interactions/QuestionField.js +89 -8
- package/dist/chat/interactions/QuestionForm.d.ts +3 -1
- package/dist/chat/interactions/QuestionForm.js +48 -10
- package/dist/chat/interactions/SecretInput.d.ts +32 -0
- package/dist/chat/interactions/SecretInput.js +72 -0
- package/dist/chat/interactions/card-ui.d.ts +5 -3
- package/dist/chat/interactions/card-ui.js +5 -3
- package/dist/chat/interactions/index.d.ts +2 -1
- package/dist/chat/interactions/index.js +2 -1
- package/dist/chat/sidebar/SessionSidebar.js +2 -0
- package/dist/chat/sidebar/SidebarFilterMenu.d.ts +7 -2
- package/dist/chat/sidebar/SidebarFilterMenu.js +26 -2
- package/dist/chat/sidebar/SidebarSessionRow.d.ts +3 -1
- package/dist/chat/sidebar/SidebarSessionRow.js +8 -3
- package/dist/chat/sidebar/sidebar-live.js +8 -4
- package/dist/chat/transcript/AuthFailureCard.d.ts +34 -0
- package/dist/chat/transcript/AuthFailureCard.js +358 -0
- package/dist/chat/transcript/InteractionToolBody.js +12 -2
- package/dist/chat/transcript/actions.d.ts +24 -1
- package/dist/chat/transcript/index.d.ts +3 -2
- package/dist/chat/transcript/index.js +2 -1
- package/dist/chat/transcript/notices.d.ts +2 -1
- package/dist/chat/transcript/notices.js +13 -1
- package/dist/chat/transcript/script-input.d.ts +1 -1
- package/dist/chat/transcript/shell-block.js +1 -1
- package/dist/components/HowItWorks.d.ts +8 -1
- package/dist/components/HowItWorks.js +2 -2
- package/dist/components/RowActionsMenu.d.ts +6 -1
- package/dist/components/RowActionsMenu.js +4 -0
- package/dist/core.css +24 -0
- package/dist/dist/{index-WlE93Q6d.d.ts → index-BI6RZc60.d.ts} +36 -3
- package/dist/dist/index-f-XWIoYo.d.ts +1 -0
- package/dist/dist/index.d.ts +6 -0
- package/dist/dist/sandbox-B4OW6oNx.d.ts +2 -0
- package/dist/dist/timeout-B5pO5I5a.d.ts +30 -0
- package/dist/extensions/ExtensionSettingsPage.js +1 -1
- package/dist/extensions/ExtensionSettingsSidebar.js +1 -1
- package/dist/extensions/headless/fixture-host.js +1 -1
- package/dist/extensions/headless/index.js +4 -4
- package/dist/extensions/hooks.js +1 -1
- package/dist/files/DiffsTab.js +1 -1
- package/dist/files/EditorColumn.js +1 -1
- package/dist/files/MediaDiff.js +1 -1
- package/dist/files/SearchPanel.js +121 -53
- package/dist/files/headless/name-match.js +29 -14
- package/dist/files/useEntryActions.js +1 -1
- package/dist/files/useOpenFiles.js +1 -1
- package/dist/git/WherePicker.js +2 -2
- package/dist/git/headless/environment.d.ts +6 -1
- package/dist/git/headless/environment.js +5 -2
- package/dist/git/headless/labels.d.ts +2 -0
- package/dist/git/headless/labels.js +2 -0
- package/dist/git/index.d.ts +2 -1
- package/dist/git/index.js +2 -1
- package/dist/git/useStartFromPanel.d.ts +22 -0
- package/dist/git/useStartFromPanel.js +91 -0
- package/dist/keybindings/KeyCommands.js +1 -1
- package/dist/keybindings/KeybindingsProvider.js +1 -1
- package/dist/keybindings/headless/catalog.js +2 -2
- package/dist/keybindings/headless/index.js +2 -2
- package/dist/keybindings/headless/overrides.js +1 -1
- package/dist/machines/HostSyncPanel.js +1 -1
- package/dist/machines/SyncOutcomeBadge.js +1 -1
- package/dist/machines/headless/index.js +1 -1
- package/dist/onboarding/demos/features.d.ts +9 -1
- package/dist/onboarding/demos/features.js +107 -2
- package/dist/onboarding/demos/how-it-works.d.ts +5 -1
- package/dist/onboarding/demos/how-it-works.js +120 -2
- package/dist/onboarding/headless/labels.d.ts +17 -0
- package/dist/onboarding/headless/labels.js +17 -0
- package/dist/onboarding/index.js +1 -1
- package/dist/onboarding/marks.d.ts +1 -2
- package/dist/onboarding/marks.js +4 -12
- package/dist/onboarding/steps/ReadyStep.js +1 -1
- package/dist/onboarding/steps/connect/ProviderPanel.js +1 -1
- package/dist/onboarding/tutorials.d.ts +3 -1
- package/dist/onboarding/tutorials.js +2 -1
- package/dist/palette/app-sources.js +1 -1
- package/dist/session/ArtifactsPanel.js +1 -1
- package/dist/session/PanelAttention.d.ts +14 -6
- package/dist/session/PanelAttention.js +35 -24
- package/dist/session/PlanTracker.d.ts +54 -0
- package/dist/session/PlanTracker.js +412 -0
- package/dist/session/ProjectHome.d.ts +15 -2
- package/dist/session/ProjectHome.js +158 -85
- package/dist/session/RemindersPanel.d.ts +25 -0
- package/dist/session/RemindersPanel.js +526 -0
- package/dist/session/SecretsPanel.d.ts +19 -0
- package/dist/session/SecretsPanel.js +241 -0
- package/dist/session/SessionProvider.d.ts +26 -5
- package/dist/session/SessionProvider.js +51 -6
- package/dist/session/StepStatusIcon.d.ts +24 -0
- package/dist/session/StepStatusIcon.js +50 -0
- package/dist/session/TodoList.d.ts +4 -3
- package/dist/session/TodoList.js +6 -5
- package/dist/session/headless/fixture-host.d.ts +32 -22
- package/dist/session/headless/fixture-host.js +86 -51
- package/dist/session/headless/fixture-plans.d.ts +57 -0
- package/dist/session/headless/fixture-plans.js +141 -0
- package/dist/session/headless/fixture-schedules.d.ts +49 -0
- package/dist/session/headless/fixture-schedules.js +133 -0
- package/dist/session/headless/home-layout.d.ts +10 -2
- package/dist/session/headless/home-layout.js +7 -2
- package/dist/session/headless/host.d.ts +85 -13
- package/dist/session/headless/index.d.ts +5 -3
- package/dist/session/headless/index.js +6 -4
- package/dist/session/headless/labels.d.ts +95 -12
- package/dist/session/headless/labels.js +67 -18
- package/dist/session/headless/plans.d.ts +53 -0
- package/dist/session/headless/plans.js +78 -0
- package/dist/session/headless/reminder-labels.d.ts +63 -0
- package/dist/session/headless/reminder-labels.js +84 -0
- package/dist/session/headless/schedules.d.ts +93 -0
- package/dist/session/headless/schedules.js +190 -0
- package/dist/session/headless/secrets.d.ts +28 -0
- package/dist/session/headless/secrets.js +48 -0
- package/dist/session/index.d.ts +7 -5
- package/dist/session/index.js +6 -4
- package/dist/session/testing/contract.d.ts +18 -5
- package/dist/session/testing/contract.js +351 -43
- package/dist/session/testing/index.d.ts +4 -2
- package/dist/session/testing/index.js +4 -2
- package/dist/settings/headless/catalog.js +17 -1
- package/dist/settings/headless/index.d.ts +2 -2
- package/dist/settings/headless/index.js +3 -3
- package/dist/settings/headless/labels.d.ts +0 -2
- package/dist/settings/headless/labels.js +0 -2
- package/dist/settings/headless/layout.js +7 -1
- package/dist/settings/headless/providers.d.ts +17 -1
- package/dist/settings/headless/providers.js +19 -1
- package/dist/settings/headless/search.d.ts +1 -1
- package/dist/settings/rows.d.ts +1 -1
- package/dist/settings/rows.js +2 -2
- package/dist/settings/sections/appearance/AppearanceSection.js +2 -2
- package/dist/settings/sections/claude-import/ClaudeImportDialog.js +1 -1
- package/dist/settings/sections/editor/EditorSection.js +1 -1
- package/dist/settings/sections/environments/EnvironmentsSection.js +1 -1
- package/dist/settings/sections/extensions/ChangeOriginDialog.js +1 -1
- package/dist/settings/sections/extensions/CreateExtensionDialog.js +1 -1
- package/dist/settings/sections/extensions/ExtensionsSection.js +1 -1
- package/dist/settings/sections/host-catalog/HostCatalogSection.js +1 -1
- package/dist/settings/sections/instructions/InstructionsSection.js +1 -1
- package/dist/settings/sections/mcp/McpSection.js +1 -1
- package/dist/settings/sections/mcp/McpServerRow.js +1 -1
- package/dist/settings/sections/models/ModelRows.js +1 -1
- package/dist/settings/sections/providers/ProvidersSection.js +209 -201
- package/dist/settings/sections/providers/ServerProvidersSection.js +1 -1
- package/dist/settings/sections/shared/catalog.js +1 -1
- package/dist/settings/sections/skills/SkillsSection.js +1 -1
- package/dist/styles.css +59 -1
- package/dist/terminal/HostTerminalSurface.js +2 -2
- package/dist/workspace/PanelContentView.d.ts +22 -4
- package/dist/workspace/PanelContentView.js +112 -16
- package/dist/workspace/PanelGlyph.d.ts +21 -0
- package/dist/workspace/PanelGlyph.js +33 -0
- package/dist/workspace/PanelHome.js +5 -3
- package/dist/workspace/PanelStrip.js +11 -4
- package/dist/workspace/PanelToolbar.d.ts +32 -0
- package/dist/workspace/PanelToolbar.js +194 -0
- package/dist/workspace/WorkspaceProvider.d.ts +3 -1
- package/dist/workspace/WorkspaceProvider.js +6 -2
- package/dist/workspace/extension-tabs.js +5 -2
- package/dist/workspace/headless/host.d.ts +4 -0
- package/dist/workspace/headless/index.d.ts +3 -1
- package/dist/workspace/headless/index.js +4 -2
- package/dist/workspace/headless/labels.d.ts +10 -0
- package/dist/workspace/headless/labels.js +11 -1
- package/dist/workspace/headless/pages.d.ts +15 -0
- package/dist/workspace/headless/pages.js +49 -0
- package/dist/workspace/headless/tab-mark.d.ts +14 -0
- package/dist/workspace/headless/tab-mark.js +27 -0
- package/dist/workspace/headless/view.d.ts +7 -1
- package/dist/workspace/index.d.ts +3 -2
- package/dist/workspace/index.js +3 -2
- package/dist/workspace/testing/index.js +6 -0
- package/dist/workspace/workspace-key-commands.js +3 -3
- package/package.json +2 -2
- package/src/styles/motion.css +13 -0
- package/src/styles/onboarding.css +0 -1
- package/src/styles/primitives.css +10 -0
- package/src/styles/workspace.css +17 -0
- package/dist/session/TodosPanel.d.ts +0 -19
- package/dist/session/TodosPanel.js +0 -251
- package/dist/session/headless/todos.d.ts +0 -22
- package/dist/session/headless/todos.js +0 -38
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { InboxPlans } from "./headless/plans.js";
|
|
2
|
+
import { CSSProperties } from "react";
|
|
3
|
+
import { PlanView } from "zidane/chat";
|
|
4
|
+
//#region src/session/PlanTracker.d.ts
|
|
5
|
+
/** Props for {@link PlanTracker}. */
|
|
6
|
+
interface PlanTrackerProps {
|
|
7
|
+
/** The session the plan belongs to. */
|
|
8
|
+
sessionId: string;
|
|
9
|
+
/** The plan to show. */
|
|
10
|
+
plan: PlanView;
|
|
11
|
+
/** Leave out the title row (a "Recent" row opened already shows it). */
|
|
12
|
+
hideHeader?: boolean;
|
|
13
|
+
/** Extra classes on the root element. */
|
|
14
|
+
className?: string;
|
|
15
|
+
/** Inline styles on the root element. */
|
|
16
|
+
style?: CSSProperties;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The tone of a plan's state chip.
|
|
20
|
+
*
|
|
21
|
+
* @param plan - The plan.
|
|
22
|
+
*/
|
|
23
|
+
declare function planStateTone(plan: PlanView): 'accent' | 'warn' | 'success' | 'muted';
|
|
24
|
+
/**
|
|
25
|
+
* A session's plans for the Inbox: the one in progress and the recent ones. Reads the session from the host once.
|
|
26
|
+
*
|
|
27
|
+
* @param sessionId - The session.
|
|
28
|
+
*/
|
|
29
|
+
declare function useInboxPlans(sessionId: string): InboxPlans;
|
|
30
|
+
/**
|
|
31
|
+
* Renders one plan with its step edits, retry, add box, tally, and the plan's stop, resume and drop.
|
|
32
|
+
*
|
|
33
|
+
* @param props - The {@link PlanTrackerProps}.
|
|
34
|
+
*/
|
|
35
|
+
declare function PlanTracker({ sessionId, plan, hideHeader, className, style }: PlanTrackerProps): import("react").JSX.Element;
|
|
36
|
+
/** Props for {@link RecentPlans}. */
|
|
37
|
+
interface RecentPlansProps {
|
|
38
|
+
/** The session the plans belong to. */
|
|
39
|
+
sessionId: string;
|
|
40
|
+
/** Closed plans, newest first (`useInboxPlans`). */
|
|
41
|
+
plans: readonly PlanView[];
|
|
42
|
+
/** Extra classes on the root element. */
|
|
43
|
+
className?: string;
|
|
44
|
+
/** Inline styles on the root element. */
|
|
45
|
+
style?: CSSProperties;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The Inbox's "Recent" plans: one line each (title, how it ended, its tally), opened in place to read its steps.
|
|
49
|
+
*
|
|
50
|
+
* @param props - The {@link RecentPlansProps}.
|
|
51
|
+
*/
|
|
52
|
+
declare function RecentPlans({ sessionId, plans, className, style }: RecentPlansProps): import("react").JSX.Element;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { PlanTracker, PlanTrackerProps, RecentPlans, RecentPlansProps, planStateTone, useInboxPlans };
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import { IconButton } from "../components/IconButton.js";
|
|
2
|
+
import { buttonClass } from "../components/button.js";
|
|
3
|
+
import { MetaChip } from "../components/Form.js";
|
|
4
|
+
import { useMinuteTick } from "../hooks/useMinuteTick.js";
|
|
5
|
+
import { inboxPlans } from "./headless/plans.js";
|
|
6
|
+
import { useSessionHost, useSessionPlans } from "./SessionProvider.js";
|
|
7
|
+
import { useSessionLabels } from "./useSessionLabels.js";
|
|
8
|
+
import { ProseMarkdown } from "../chat/transcript/ProseMarkdown.js";
|
|
9
|
+
import { StepStatusIcon } from "./StepStatusIcon.js";
|
|
10
|
+
import { isDoneTodo } from "./TodoList.js";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
import { useEffect, useRef, useState } from "react";
|
|
13
|
+
import { buildPlanResumeMessage, buildStepRetryMessage, describeTime, planProgress } from "zidane/chat/pure";
|
|
14
|
+
//#region src/session/PlanTracker.tsx
|
|
15
|
+
/**
|
|
16
|
+
* One plan as a card, its steps live as the agent works: the Inbox's
|
|
17
|
+
* "In progress" card, and a "Recent" plan opened. At parity with the TUI's
|
|
18
|
+
* todos modal.
|
|
19
|
+
*
|
|
20
|
+
* Every edit goes to the host's plan gate (`plans.edit` / `plans.control`),
|
|
21
|
+
* never to a copy here: the agent reads the same plan and is told what
|
|
22
|
+
* changed. Only "which row is mid-edit", the add box and the drop
|
|
23
|
+
* confirmation are local.
|
|
24
|
+
*
|
|
25
|
+
* On an applying or stopped plan: click a step's text to rename it (Enter
|
|
26
|
+
* saves, Esc cancels, blur saves), retry asks the agent to redo the step,
|
|
27
|
+
* cancel marks it cancelled (a step is never deleted), the box adds a step,
|
|
28
|
+
* Stop stops the plan and the run applying it, Resume asks the agent to
|
|
29
|
+
* continue a stopped plan, Drop closes it after an inline confirm. A closed
|
|
30
|
+
* plan is read-only. Without `plans.edit` there is no add, rename or
|
|
31
|
+
* cancel; without `plans.control` no stop or drop; without `plans.retry` no
|
|
32
|
+
* retry or resume.
|
|
33
|
+
*
|
|
34
|
+
* const { current, recent } = useInboxPlans(sessionId)
|
|
35
|
+
* <PlanTracker sessionId={sessionId} plan={current} />
|
|
36
|
+
*/
|
|
37
|
+
const INPUT_CLS = "zg-well flex-1 min-w-0 font-mono text-zg-label px-2.5 py-1 placeholder:text-[var(--zg-text-subtle)]";
|
|
38
|
+
const GHOST_BTN = buttonClass({
|
|
39
|
+
variant: "ghost",
|
|
40
|
+
size: "xs"
|
|
41
|
+
});
|
|
42
|
+
const ROW_ACTION_CLS = "opacity-0 group-hover:opacity-100 focus-visible:opacity-100";
|
|
43
|
+
/** The quiet note after a step's title: who cancelled it, or that it was added after approval. */
|
|
44
|
+
function stepMarker(step, labels) {
|
|
45
|
+
if (step.status === "cancelled" && step.cancelledBy === "user") return labels.stepCancelledByYou;
|
|
46
|
+
if (step.status === "cancelled" && step.cancelledBy === "agent") return labels.stepDroppedByAgent;
|
|
47
|
+
return step.added ? labels.stepAdded : null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The tone of a plan's state chip.
|
|
51
|
+
*
|
|
52
|
+
* @param plan - The plan.
|
|
53
|
+
*/
|
|
54
|
+
function planStateTone(plan) {
|
|
55
|
+
if (plan.state === "applying") return plan.possiblyInterrupted ? "muted" : "accent";
|
|
56
|
+
if (plan.state === "stopped") return "warn";
|
|
57
|
+
return plan.state === "done" ? "success" : "muted";
|
|
58
|
+
}
|
|
59
|
+
const NO_INBOX_PLANS = {
|
|
60
|
+
current: null,
|
|
61
|
+
recent: []
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* A session's plans for the Inbox: the one in progress and the recent ones. Reads the session from the host once.
|
|
65
|
+
*
|
|
66
|
+
* @param sessionId - The session.
|
|
67
|
+
*/
|
|
68
|
+
function useInboxPlans(sessionId) {
|
|
69
|
+
const refresh = useSessionHost().plans?.refresh;
|
|
70
|
+
const snap = useSessionPlans(sessionId);
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
refresh?.(sessionId);
|
|
73
|
+
}, [sessionId, refresh]);
|
|
74
|
+
return snap ? inboxPlans(snap.plans) : NO_INBOX_PLANS;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Renders one plan with its step edits, retry, add box, tally, and the plan's stop, resume and drop.
|
|
78
|
+
*
|
|
79
|
+
* @param props - The {@link PlanTrackerProps}.
|
|
80
|
+
*/
|
|
81
|
+
function PlanTracker({ sessionId, plan, hideHeader = false, className, style }) {
|
|
82
|
+
const labels = useSessionLabels();
|
|
83
|
+
const host = useSessionHost().plans;
|
|
84
|
+
const edit = host?.edit;
|
|
85
|
+
const control = host?.control;
|
|
86
|
+
const retryRun = host?.retry;
|
|
87
|
+
const steps = plan?.steps ?? [];
|
|
88
|
+
const applying = plan?.state === "applying";
|
|
89
|
+
const stopped = plan?.state === "stopped";
|
|
90
|
+
const open = applying || stopped;
|
|
91
|
+
const canEdit = open && Boolean(edit);
|
|
92
|
+
const progress = planProgress(plan);
|
|
93
|
+
const hasActions = Boolean(open && control || stopped && retryRun);
|
|
94
|
+
const stopStep = plan.stoppedAt ? steps.findIndex((s) => s.id === plan.stoppedAt) + 1 : 0;
|
|
95
|
+
const [editingId, setEditingId] = useState(null);
|
|
96
|
+
const [draft, setDraft] = useState("");
|
|
97
|
+
const [adding, setAdding] = useState("");
|
|
98
|
+
const [error, setError] = useState(null);
|
|
99
|
+
const [confirmDrop, setConfirmDrop] = useState(false);
|
|
100
|
+
const editRef = useRef(null);
|
|
101
|
+
const planKey = `${plan.id}:${open}`;
|
|
102
|
+
const [shownKey, setShownKey] = useState(planKey);
|
|
103
|
+
if (shownKey !== planKey) {
|
|
104
|
+
setShownKey(planKey);
|
|
105
|
+
setEditingId(null);
|
|
106
|
+
setConfirmDrop(false);
|
|
107
|
+
}
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (editingId) {
|
|
110
|
+
editRef.current?.focus();
|
|
111
|
+
editRef.current?.select();
|
|
112
|
+
}
|
|
113
|
+
}, [editingId]);
|
|
114
|
+
/** Runs a host call; its rejection (the gate's reason) shows under the list. */
|
|
115
|
+
const run = (call) => {
|
|
116
|
+
if (!call) return;
|
|
117
|
+
setError(null);
|
|
118
|
+
call.catch((err) => setError(err instanceof Error ? err.message : String(err)));
|
|
119
|
+
};
|
|
120
|
+
const startEdit = (step) => {
|
|
121
|
+
if (!canEdit) return;
|
|
122
|
+
setEditingId(step.id);
|
|
123
|
+
setDraft(step.title);
|
|
124
|
+
};
|
|
125
|
+
const saveEdit = () => {
|
|
126
|
+
if (!editingId) return;
|
|
127
|
+
const step = steps.find((s) => s.id === editingId);
|
|
128
|
+
const title = draft.trim();
|
|
129
|
+
if (step && title.length > 0 && title !== step.title) run(edit?.(sessionId, plan.id, {
|
|
130
|
+
kind: "rename",
|
|
131
|
+
stepId: step.id,
|
|
132
|
+
title
|
|
133
|
+
}));
|
|
134
|
+
setEditingId(null);
|
|
135
|
+
};
|
|
136
|
+
const submitAdd = () => {
|
|
137
|
+
const title = adding.trim();
|
|
138
|
+
if (title.length === 0) return;
|
|
139
|
+
run(edit?.(sessionId, plan.id, {
|
|
140
|
+
kind: "add",
|
|
141
|
+
title
|
|
142
|
+
}));
|
|
143
|
+
setAdding("");
|
|
144
|
+
};
|
|
145
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
146
|
+
className: ["flex flex-col gap-2 py-2", className].filter(Boolean).join(" "),
|
|
147
|
+
style,
|
|
148
|
+
"data-plan-state": plan.state,
|
|
149
|
+
"data-testid": "plan-tracker",
|
|
150
|
+
children: [
|
|
151
|
+
!hideHeader && /* @__PURE__ */ jsxs("div", {
|
|
152
|
+
className: "flex items-center gap-2 px-2 min-w-0",
|
|
153
|
+
children: [
|
|
154
|
+
/* @__PURE__ */ jsx("span", {
|
|
155
|
+
className: "flex-1 min-w-0 truncate text-zg-ui font-medium text-[var(--zg-text)]",
|
|
156
|
+
title: plan.title || void 0,
|
|
157
|
+
children: plan.title || labels.planUntitled
|
|
158
|
+
}),
|
|
159
|
+
/* @__PURE__ */ jsx(MetaChip, {
|
|
160
|
+
tone: planStateTone(plan),
|
|
161
|
+
children: labels.planState[plan.state]
|
|
162
|
+
}),
|
|
163
|
+
/* @__PURE__ */ jsx("span", {
|
|
164
|
+
"data-testid": "todo-progress",
|
|
165
|
+
children: /* @__PURE__ */ jsx(MetaChip, { children: labels.todosProgress(progress.completed + progress.cancelled, progress.total) })
|
|
166
|
+
})
|
|
167
|
+
]
|
|
168
|
+
}),
|
|
169
|
+
stopped && /* @__PURE__ */ jsx("p", {
|
|
170
|
+
className: "m-0 px-2 text-zg-meta text-[var(--zg-warn)]",
|
|
171
|
+
children: labels.planStopped(stopStep > 0 ? stopStep : null, plan.stopReason)
|
|
172
|
+
}),
|
|
173
|
+
applying && plan.possiblyInterrupted && /* @__PURE__ */ jsx("p", {
|
|
174
|
+
className: "m-0 px-2 text-zg-meta text-[var(--zg-text-muted)]",
|
|
175
|
+
children: labels.planMaybeInterrupted
|
|
176
|
+
}),
|
|
177
|
+
plan.body && /* @__PURE__ */ jsx("div", {
|
|
178
|
+
"data-testid": "plan-body",
|
|
179
|
+
className: "px-2 text-zg-ui text-[var(--zg-text)] zg-pretty",
|
|
180
|
+
children: /* @__PURE__ */ jsx(ProseMarkdown, { children: plan.body })
|
|
181
|
+
}),
|
|
182
|
+
steps.length === 0 && /* @__PURE__ */ jsx("p", {
|
|
183
|
+
className: "m-0 px-2 text-zg-meta text-[var(--zg-text-muted)]",
|
|
184
|
+
children: labels.planNoSteps
|
|
185
|
+
}),
|
|
186
|
+
/* @__PURE__ */ jsx("ol", {
|
|
187
|
+
className: "flex flex-col gap-1.5 m-0 px-2 list-none",
|
|
188
|
+
children: steps.map((step, i) => {
|
|
189
|
+
const dim = isDoneTodo(step.status);
|
|
190
|
+
const marker = stepMarker(step, labels);
|
|
191
|
+
const haltedHere = stopped && step.id === plan.stoppedAt && !dim;
|
|
192
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
193
|
+
"data-status": step.status,
|
|
194
|
+
className: "group flex items-start gap-2 zg-tray rounded-zg-md px-2.5 py-2",
|
|
195
|
+
children: [
|
|
196
|
+
/* @__PURE__ */ jsx("span", {
|
|
197
|
+
className: "flex items-center h-6 shrink-0",
|
|
198
|
+
children: /* @__PURE__ */ jsx(StepStatusIcon, {
|
|
199
|
+
state: haltedHere ? "stopped" : step.status,
|
|
200
|
+
label: labels.todoStatus(step.status),
|
|
201
|
+
className: "text-zg-ui"
|
|
202
|
+
})
|
|
203
|
+
}),
|
|
204
|
+
/* @__PURE__ */ jsxs("span", {
|
|
205
|
+
className: "zg-meta leading-6 w-4 shrink-0",
|
|
206
|
+
children: [i + 1, "."]
|
|
207
|
+
}),
|
|
208
|
+
/* @__PURE__ */ jsxs("div", {
|
|
209
|
+
className: "flex-1 min-w-0 flex flex-col",
|
|
210
|
+
children: [
|
|
211
|
+
editingId === step.id ? /* @__PURE__ */ jsx("input", {
|
|
212
|
+
ref: editRef,
|
|
213
|
+
type: "text",
|
|
214
|
+
value: draft,
|
|
215
|
+
spellCheck: false,
|
|
216
|
+
"aria-label": labels.todoEdit,
|
|
217
|
+
onChange: (e) => setDraft(e.target.value),
|
|
218
|
+
onBlur: saveEdit,
|
|
219
|
+
onKeyDown: (e) => {
|
|
220
|
+
if (e.key === "Enter") saveEdit();
|
|
221
|
+
if (e.key === "Escape") setEditingId(null);
|
|
222
|
+
},
|
|
223
|
+
className: INPUT_CLS
|
|
224
|
+
}) : /* @__PURE__ */ jsx("button", {
|
|
225
|
+
type: "button",
|
|
226
|
+
disabled: !canEdit,
|
|
227
|
+
onClick: () => startEdit(step),
|
|
228
|
+
title: canEdit ? labels.todoEdit : step.title,
|
|
229
|
+
className: `min-w-0 text-left text-zg-ui leading-6 font-medium bg-transparent border-0 p-0 cursor-text disabled:cursor-default zg-balance transition-colors ${dim ? "text-[var(--zg-text-muted)]" : "text-[var(--zg-text)]"}${step.status === "cancelled" ? " line-through" : ""}`,
|
|
230
|
+
children: step.title
|
|
231
|
+
}),
|
|
232
|
+
step.description && /* @__PURE__ */ jsx("span", {
|
|
233
|
+
className: "text-zg-meta mt-0.5 text-[var(--zg-text-muted)] zg-pretty",
|
|
234
|
+
children: step.description
|
|
235
|
+
}),
|
|
236
|
+
step.note && /* @__PURE__ */ jsx("span", {
|
|
237
|
+
className: "text-zg-meta leading-4 text-[var(--zg-text-subtle)] italic zg-pretty",
|
|
238
|
+
children: labels.stepAgentNote(step.note)
|
|
239
|
+
})
|
|
240
|
+
]
|
|
241
|
+
}),
|
|
242
|
+
marker && /* @__PURE__ */ jsx("span", {
|
|
243
|
+
className: "zg-meta shrink-0",
|
|
244
|
+
children: marker
|
|
245
|
+
}),
|
|
246
|
+
open && retryRun && /* @__PURE__ */ jsx(IconButton, {
|
|
247
|
+
size: "xs",
|
|
248
|
+
icon: "i-ph-arrow-clockwise",
|
|
249
|
+
label: labels.todoRetry,
|
|
250
|
+
title: labels.todoRetryHint,
|
|
251
|
+
onClick: () => run(retryRun(sessionId, buildStepRetryMessage(step))),
|
|
252
|
+
className: ROW_ACTION_CLS
|
|
253
|
+
}),
|
|
254
|
+
canEdit && !dim && /* @__PURE__ */ jsx(IconButton, {
|
|
255
|
+
size: "xs",
|
|
256
|
+
icon: "i-ph-x",
|
|
257
|
+
label: labels.stepCancel,
|
|
258
|
+
title: labels.stepCancelHint,
|
|
259
|
+
tone: "danger",
|
|
260
|
+
onClick: () => run(edit?.(sessionId, plan.id, {
|
|
261
|
+
kind: "cancel",
|
|
262
|
+
stepId: step.id
|
|
263
|
+
})),
|
|
264
|
+
className: ROW_ACTION_CLS
|
|
265
|
+
})
|
|
266
|
+
]
|
|
267
|
+
}, step.id);
|
|
268
|
+
})
|
|
269
|
+
}),
|
|
270
|
+
(error || canEdit || hasActions) && /* @__PURE__ */ jsxs("div", {
|
|
271
|
+
className: "flex flex-col gap-2 px-2",
|
|
272
|
+
children: [
|
|
273
|
+
error && /* @__PURE__ */ jsx("div", {
|
|
274
|
+
className: "text-zg-meta text-[var(--zg-warn)]",
|
|
275
|
+
role: "alert",
|
|
276
|
+
children: error
|
|
277
|
+
}),
|
|
278
|
+
canEdit && /* @__PURE__ */ jsxs("div", {
|
|
279
|
+
className: "flex items-center gap-2",
|
|
280
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
281
|
+
type: "text",
|
|
282
|
+
placeholder: labels.todoAddPlaceholder,
|
|
283
|
+
"aria-label": labels.todoAddLabel,
|
|
284
|
+
value: adding,
|
|
285
|
+
spellCheck: false,
|
|
286
|
+
onChange: (e) => setAdding(e.target.value),
|
|
287
|
+
onKeyDown: (e) => {
|
|
288
|
+
if (e.key === "Enter") submitAdd();
|
|
289
|
+
},
|
|
290
|
+
className: INPUT_CLS
|
|
291
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
292
|
+
type: "button",
|
|
293
|
+
className: GHOST_BTN,
|
|
294
|
+
disabled: adding.trim().length === 0,
|
|
295
|
+
onClick: submitAdd,
|
|
296
|
+
children: labels.todoAdd
|
|
297
|
+
})]
|
|
298
|
+
}),
|
|
299
|
+
hasActions && /* @__PURE__ */ jsx("div", {
|
|
300
|
+
className: "flex items-center justify-end gap-3 min-h-6",
|
|
301
|
+
children: confirmDrop && control ? /* @__PURE__ */ jsxs("span", {
|
|
302
|
+
className: "flex items-center gap-1.5 text-zg-meta",
|
|
303
|
+
children: [
|
|
304
|
+
/* @__PURE__ */ jsx("span", {
|
|
305
|
+
className: "text-[var(--zg-text-muted)]",
|
|
306
|
+
children: labels.planDropConfirm(applying)
|
|
307
|
+
}),
|
|
308
|
+
/* @__PURE__ */ jsx("button", {
|
|
309
|
+
type: "button",
|
|
310
|
+
className: `${GHOST_BTN} text-[var(--zg-error)]`,
|
|
311
|
+
onClick: () => {
|
|
312
|
+
run(control(sessionId, plan.id, "drop"));
|
|
313
|
+
setConfirmDrop(false);
|
|
314
|
+
},
|
|
315
|
+
children: labels.planDropYes
|
|
316
|
+
}),
|
|
317
|
+
/* @__PURE__ */ jsx("button", {
|
|
318
|
+
type: "button",
|
|
319
|
+
className: GHOST_BTN,
|
|
320
|
+
onClick: () => setConfirmDrop(false),
|
|
321
|
+
children: labels.planDropCancel
|
|
322
|
+
})
|
|
323
|
+
]
|
|
324
|
+
}) : /* @__PURE__ */ jsxs("span", {
|
|
325
|
+
className: "flex items-center gap-1",
|
|
326
|
+
children: [
|
|
327
|
+
applying && control && /* @__PURE__ */ jsx("button", {
|
|
328
|
+
type: "button",
|
|
329
|
+
className: GHOST_BTN,
|
|
330
|
+
title: labels.planStopHint,
|
|
331
|
+
onClick: () => run(control(sessionId, plan.id, "stop")),
|
|
332
|
+
children: labels.planStop
|
|
333
|
+
}),
|
|
334
|
+
stopped && retryRun && /* @__PURE__ */ jsx("button", {
|
|
335
|
+
type: "button",
|
|
336
|
+
className: GHOST_BTN,
|
|
337
|
+
title: labels.planResumeHint,
|
|
338
|
+
onClick: () => run(retryRun(sessionId, buildPlanResumeMessage(plan))),
|
|
339
|
+
children: labels.planResume
|
|
340
|
+
}),
|
|
341
|
+
open && control && /* @__PURE__ */ jsx("button", {
|
|
342
|
+
type: "button",
|
|
343
|
+
className: GHOST_BTN,
|
|
344
|
+
title: labels.planDropHint,
|
|
345
|
+
onClick: () => setConfirmDrop(true),
|
|
346
|
+
children: labels.planDrop
|
|
347
|
+
})
|
|
348
|
+
]
|
|
349
|
+
})
|
|
350
|
+
})
|
|
351
|
+
]
|
|
352
|
+
})
|
|
353
|
+
]
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* The Inbox's "Recent" plans: one line each (title, how it ended, its tally), opened in place to read its steps.
|
|
358
|
+
*
|
|
359
|
+
* @param props - The {@link RecentPlansProps}.
|
|
360
|
+
*/
|
|
361
|
+
function RecentPlans({ sessionId, plans, className, style }) {
|
|
362
|
+
const labels = useSessionLabels();
|
|
363
|
+
const [open, setOpen] = useState(null);
|
|
364
|
+
useMinuteTick();
|
|
365
|
+
const now = Date.now();
|
|
366
|
+
return /* @__PURE__ */ jsx("ul", {
|
|
367
|
+
className: ["m-0 p-0 list-none flex flex-col gap-1", className].filter(Boolean).join(" "),
|
|
368
|
+
style,
|
|
369
|
+
children: plans.map((plan) => {
|
|
370
|
+
const progress = planProgress(plan);
|
|
371
|
+
const expanded = open === plan.id;
|
|
372
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
373
|
+
"data-testid": "recent-plan",
|
|
374
|
+
"data-plan-state": plan.state,
|
|
375
|
+
className: "zg-raised border rounded-zg-lg overflow-hidden",
|
|
376
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
377
|
+
type: "button",
|
|
378
|
+
"aria-expanded": expanded,
|
|
379
|
+
onClick: () => setOpen(expanded ? null : plan.id),
|
|
380
|
+
className: "flex items-center gap-2 w-full px-3 py-2 text-left bg-transparent border-0 cursor-pointer hover:bg-[var(--zg-row-hover)]",
|
|
381
|
+
children: [
|
|
382
|
+
/* @__PURE__ */ jsx("span", {
|
|
383
|
+
className: "flex-1 min-w-0 truncate text-zg-ui text-[var(--zg-text)]",
|
|
384
|
+
children: plan.title || labels.planUntitled
|
|
385
|
+
}),
|
|
386
|
+
/* @__PURE__ */ jsx(MetaChip, {
|
|
387
|
+
title: new Date(plan.createdAt).toLocaleString(),
|
|
388
|
+
className: "tabular-nums",
|
|
389
|
+
children: describeTime(plan.createdAt, now)
|
|
390
|
+
}),
|
|
391
|
+
/* @__PURE__ */ jsx(MetaChip, {
|
|
392
|
+
tone: planStateTone(plan),
|
|
393
|
+
children: labels.planState[plan.state]
|
|
394
|
+
}),
|
|
395
|
+
/* @__PURE__ */ jsx(MetaChip, { children: labels.todosProgress(progress.completed + progress.cancelled, progress.total) }),
|
|
396
|
+
/* @__PURE__ */ jsx("span", {
|
|
397
|
+
"aria-hidden": true,
|
|
398
|
+
className: `${expanded ? "i-ph-caret-up" : "i-ph-caret-down"} text-zg-label text-[var(--zg-text-muted)]`
|
|
399
|
+
})
|
|
400
|
+
]
|
|
401
|
+
}), expanded && /* @__PURE__ */ jsx(PlanTracker, {
|
|
402
|
+
sessionId,
|
|
403
|
+
plan,
|
|
404
|
+
hideHeader: true,
|
|
405
|
+
className: "px-1 pb-2"
|
|
406
|
+
})]
|
|
407
|
+
}, plan.id);
|
|
408
|
+
})
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
//#endregion
|
|
412
|
+
export { PlanTracker, RecentPlans, planStateTone, useInboxPlans };
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { WorkspacePanels } from "../workspace/headless/host.js";
|
|
2
2
|
import { PanelOpenEvent } from "../workspace/PanelContentView.js";
|
|
3
3
|
import { CSSProperties, ReactNode } from "react";
|
|
4
|
+
import { PanelStartSession } from "zidane/chat/pure";
|
|
4
5
|
//#region src/session/ProjectHome.d.ts
|
|
6
|
+
/** What a block row's start answered: done, or why not in words. */
|
|
7
|
+
type ProjectHomeStartResult = {
|
|
8
|
+
ok: true;
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
5
13
|
/** The project a home is for. */
|
|
6
14
|
interface ProjectHomeProject {
|
|
7
15
|
/** Its name (the folder's). */
|
|
@@ -57,6 +65,11 @@ interface ProjectHomeProps {
|
|
|
57
65
|
onOpenSession?: (sessionId: string) => void;
|
|
58
66
|
/** Opens a block row's path. */
|
|
59
67
|
onOpenPath?: (path: string, event?: PanelOpenEvent) => void;
|
|
68
|
+
/**
|
|
69
|
+
* A block row's "start a session" (a pull request's Open in worktree, a ticket's Open here): sets up the new-chat
|
|
70
|
+
* draft (`useStartFromPanel`, `zidane-ui/git`). A failure shows on the block. Absent: those buttons are not offered.
|
|
71
|
+
*/
|
|
72
|
+
onStartSession?: (start: PanelStartSession) => Promise<ProjectHomeStartResult>;
|
|
60
73
|
/** A click on the repository chip (its web page, or the working tree). Absent: the chip is plain text. */
|
|
61
74
|
onOpenRepo?: () => void;
|
|
62
75
|
/** A click on the project's path chip: open the Files panel. Absent: the chip is plain text. */
|
|
@@ -77,6 +90,6 @@ interface ProjectHomeProps {
|
|
|
77
90
|
*
|
|
78
91
|
* @param props - The {@link ProjectHomeProps}.
|
|
79
92
|
*/
|
|
80
|
-
declare function ProjectHome({ panels, cwd, projectKey, project, switcher, blocksUnavailable, defaultBlocks, onOpenSession, onOpenPath, onOpenRepo, onOpenFiles, onRevealPath, onOpenInEditor, now: nowProp, className, style }: ProjectHomeProps): import("react").JSX.Element;
|
|
93
|
+
declare function ProjectHome({ panels, cwd, projectKey, project, switcher, blocksUnavailable, defaultBlocks, onOpenSession, onOpenPath, onStartSession, onOpenRepo, onOpenFiles, onRevealPath, onOpenInEditor, now: nowProp, className, style }: ProjectHomeProps): import("react").JSX.Element;
|
|
81
94
|
//#endregion
|
|
82
|
-
export { ProjectHome, ProjectHomeProject, ProjectHomeProps, ProjectHomeRepo, ProjectHomeSwitcher };
|
|
95
|
+
export { ProjectHome, ProjectHomeProject, ProjectHomeProps, ProjectHomeRepo, ProjectHomeStartResult, ProjectHomeSwitcher };
|