@nextclaw/ui 0.14.0 → 0.14.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/dist/assets/{api-B50yVdT8.js → api-dQ6uQSZG.js} +3 -3
- package/dist/assets/channels-list-page-DfpjB8XB.js +8 -0
- package/dist/assets/chat-page-D3QaEqjs.js +105 -0
- package/dist/assets/config-split-page-CeFfbaqc.js +1 -0
- package/dist/assets/{confirm-dialog-DRSelLdI.js → confirm-dialog-C95Y4QPC.js} +1 -1
- package/dist/assets/desktop-update-config-CcK6jiEb.js +1 -0
- package/dist/assets/{dist-D19wiQwB.js → dist-DTGzeil6.js} +1 -1
- package/dist/assets/{dist-NZRV-BxD.js → dist-fGogBmPA.js} +1 -1
- package/dist/assets/doc-browser-CuBTcBEZ.js +1 -0
- package/dist/assets/doc-browser-DVHhEb96.js +1 -0
- package/dist/assets/{doc-browser-context-C8KPbj-p.js → doc-browser-context-BfMXwnrz.js} +1 -1
- package/dist/assets/{ellipsis-BYy8TP0A.js → ellipsis-D2F4KMiU.js} +1 -1
- package/dist/assets/{external-link-528k6MDD.js → external-link-CcgtBK26.js} +1 -1
- package/dist/assets/index-ByJCbQqr.css +1 -0
- package/dist/assets/index-DjXqiloY.js +103 -0
- package/dist/assets/mcp-marketplace-page-98-V__3u.js +1 -0
- package/dist/assets/mcp-marketplace-page-BNq_PNmO.js +40 -0
- package/dist/assets/model-config-page-aAUkZkSX.js +1 -0
- package/dist/assets/plus-1Rxl5FlV.js +1 -0
- package/dist/assets/provider-scoped-model-input-we4_Z4gP.js +1 -0
- package/dist/assets/providers-config-page-CtMkPSyu.js +1 -0
- package/dist/assets/{react-Dsotw5vM.js → react-CTqdhFMk.js} +1 -1
- package/dist/assets/remote-fQ7N_r8u.js +1 -0
- package/dist/assets/rotate-cw-CzfIeAJj.js +1 -0
- package/dist/assets/runtime-config-page-TD1UrTbG.js +1 -0
- package/dist/assets/{save-CHDnDTok.js → save-C9fKWfVB.js} +1 -1
- package/dist/assets/search-D5FQ5q0X.js +1 -0
- package/dist/assets/search-config-page-AMEJJNIS.js +1 -0
- package/dist/assets/secrets-config-page-CcgJnvBO.js +3 -0
- package/dist/assets/select-Cu5n0E-3.js +41 -0
- package/dist/assets/{tag-chip-Cr8GwpRE.js → tag-chip-C5aOtjxu.js} +1 -1
- package/dist/assets/use-config-D8TESeo6.js +1 -0
- package/dist/assets/x-1qETdQ70.js +1 -0
- package/dist/index.html +14 -27
- package/package.json +9 -9
- package/src/app/presenters/app.presenter.ts +2 -0
- package/src/features/account/components/account-panel.tsx +2 -2
- package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +12 -63
- package/src/features/chat/components/conversation/chat-conversation-content.tsx +11 -50
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +1 -0
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +15 -2
- package/src/features/chat/features/input/components/chat-input-bar.container.tsx +122 -85
- package/src/features/chat/features/input/hooks/use-chat-input-bar-query-state.ts +120 -0
- package/src/features/chat/features/input/hooks/use-chat-model-favorites.ts +87 -0
- package/src/features/chat/features/input/utils/__tests__/chat-input-bar.utils.test.ts +66 -41
- package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +1 -0
- package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +22 -36
- package/src/features/chat/features/input/utils/chat-input-toolbar.utils.ts +80 -52
- package/src/features/chat/features/message/components/__tests__/chat-inline-panel-app-card.test.tsx +89 -0
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +9 -1
- package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +115 -0
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +4 -0
- package/src/features/chat/features/message/utils/__tests__/chat-message-file-operation.utils.test.ts +310 -0
- package/src/features/chat/features/message/utils/__tests__/chat-message-show-content-tool-card.utils.test.ts +119 -1
- package/src/features/chat/features/message/utils/__tests__/chat-message-test.utils.ts +43 -0
- package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +1 -346
- package/src/features/chat/features/message/utils/chat-inline-panel-app-card.utils.ts +51 -0
- package/src/features/chat/features/message/utils/chat-message-show-content-tool-card.utils.ts +28 -5
- package/src/features/chat/features/message/utils/chat-message-tool-card.utils.ts +14 -9
- package/src/features/chat/features/message/utils/file-operation/diff.utils.ts +39 -36
- package/src/features/chat/features/message/utils/file-operation/line-builder.utils.ts +46 -38
- package/src/features/chat/features/message/utils/file-operation/parsed-block.utils.ts +18 -15
- package/src/features/chat/features/ncp/hooks/__tests__/use-ui-show-content-event.test.tsx +1 -0
- package/src/features/chat/features/ncp/utils/ncp-chat-query-derived.utils.ts +11 -3
- package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +27 -0
- package/src/features/chat/features/session/components/session-header/__tests__/chat-session-project-badge.test.tsx +25 -25
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +19 -1
- package/src/features/chat/features/session/components/session-header/chat-session-metadata-dialog.tsx +46 -0
- package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +15 -2
- package/src/features/chat/features/session/hooks/__tests__/use-selected-session-context-window-indicator.test.tsx +63 -0
- package/src/features/chat/features/session/hooks/use-selected-session-context-window-indicator.ts +7 -10
- package/src/features/chat/features/session/utils/__tests__/ncp-session-adapter.utils.test.ts +8 -0
- package/src/features/chat/features/session/utils/ncp-session-adapter.utils.ts +2 -0
- package/src/features/chat/features/session-type/components/__tests__/chat-sidebar-create-menu.test.tsx +24 -0
- package/src/features/chat/features/session-type/components/chat-sidebar-create-menu.tsx +10 -1
- package/src/features/chat/features/session-type/hooks/use-chat-session-type-state.ts +1 -0
- package/src/features/chat/features/session-type/utils/chat-session-type.utils.ts +4 -0
- package/src/features/chat/features/welcome/components/__tests__/chat-conversation-welcome.test.tsx +193 -0
- package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +123 -0
- package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +104 -0
- package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +72 -0
- package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +54 -0
- package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +132 -0
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +82 -0
- package/src/features/chat/features/welcome/components/chat-welcome.tsx +121 -0
- package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-project-options.utils.test.ts +53 -0
- package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-selection.utils.test.ts +63 -0
- package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-visibility.utils.test.ts +34 -0
- package/src/features/chat/features/welcome/utils/chat-welcome-project-options.utils.ts +71 -0
- package/src/features/chat/features/welcome/utils/chat-welcome-selection.utils.ts +79 -0
- package/src/features/chat/features/welcome/utils/chat-welcome-visibility.utils.ts +17 -0
- package/src/features/chat/index.ts +1 -0
- package/src/features/chat/managers/__tests__/chat-input.manager.test.ts +93 -0
- package/src/features/chat/managers/__tests__/chat-run-snapshot.manager.test.ts +129 -0
- package/src/features/chat/managers/__tests__/chat-run.manager.test.ts +34 -0
- package/src/features/chat/managers/__tests__/chat-session-preference-sync.manager.test.ts +143 -1
- package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +30 -0
- package/src/features/chat/managers/__tests__/recent-selection.manager.test.ts +37 -14
- package/src/features/chat/managers/chat-draft-intent.manager.ts +46 -0
- package/src/features/chat/managers/chat-input.manager.ts +37 -15
- package/src/features/chat/managers/chat-run.manager.ts +3 -0
- package/src/features/chat/managers/chat-session-preference-sync.manager.ts +19 -2
- package/src/features/chat/managers/chat-thread.manager.ts +4 -0
- package/src/features/chat/managers/chat-ui.manager.ts +2 -6
- package/src/features/chat/managers/recent-selection.manager.ts +21 -67
- package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +47 -1
- package/src/features/chat/pages/ncp-chat-page.tsx +18 -0
- package/src/features/chat/stores/chat-input.store.ts +9 -1
- package/src/features/chat/stores/recent-selection.store.ts +85 -0
- package/src/features/chat/types/chat-input-bar.types.ts +5 -1
- package/src/features/marketplace/utils/marketplace-installed-cache.utils.ts +27 -23
- package/src/features/panel-apps/components/__tests__/panel-apps-list.test.tsx +137 -0
- package/src/features/panel-apps/components/panel-apps-list.tsx +119 -5
- package/src/features/panel-apps/index.ts +2 -0
- package/src/features/panel-apps/utils/panel-app-entry-match.utils.ts +17 -0
- package/src/features/settings/components/config/provider-form.tsx +284 -387
- package/src/features/settings/components/config/provider-status-badge.tsx +4 -4
- package/src/features/settings/components/config/secrets-config-form.tsx +11 -135
- package/src/features/settings/hooks/use-provider-auth-flow.ts +140 -0
- package/src/features/settings/pages/__tests__/model-config-page.test.tsx +16 -0
- package/src/features/settings/pages/secrets-config-page.tsx +2 -1
- package/src/features/settings/utils/__tests__/provider-form-support.utils.test.ts +60 -1
- package/src/features/settings/utils/__tests__/secrets-config-form.utils.test.ts +66 -0
- package/src/features/settings/utils/provider-form-context.utils.ts +131 -0
- package/src/features/settings/utils/provider-form-model.utils.ts +101 -0
- package/src/features/settings/utils/provider-form-support.utils.ts +102 -1
- package/src/features/settings/utils/secrets-config-form.utils.ts +139 -0
- package/src/features/system-status/components/config/runtime-agent-list-card.tsx +17 -11
- package/src/features/system-status/components/config/runtime-binding-list-card.tsx +14 -9
- package/src/features/system-status/components/config/runtime-config-editor.tsx +8 -5
- package/src/features/system-status/components/config/runtime-entry-list-card.tsx +14 -9
- package/src/features/system-status/components/config/runtime-settings-card.tsx +16 -7
- package/src/features/system-status/components/runtime-security-card.tsx +79 -25
- package/src/shared/components/common/__tests__/searchable-model-input.test.tsx +34 -0
- package/src/shared/components/common/provider-scoped-model-input.tsx +1 -0
- package/src/shared/components/common/searchable-model-input.tsx +102 -87
- package/src/shared/components/ui/README.md +7 -0
- package/src/shared/components/ui/popover.tsx +19 -3
- package/src/shared/components/ui/select.tsx +14 -4
- package/src/shared/hooks/use-infinite-scroll-loader.ts +14 -10
- package/src/shared/lib/api/chat-session-type.types.ts +7 -0
- package/src/shared/lib/api/index.ts +2 -0
- package/src/shared/lib/api/ncp-session.types.ts +1 -0
- package/src/shared/lib/api/preferences/preference.types.ts +22 -0
- package/src/shared/lib/api/preferences/preference.utils.ts +40 -0
- package/src/shared/lib/api/types.ts +3 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +20 -1
- package/src/shared/lib/i18n/locales/en-US/core.json +1 -0
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +10 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +20 -1
- package/src/shared/lib/i18n/locales/zh-CN/core.json +1 -0
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +10 -0
- package/dist/assets/app-presenter-provider-BI-ewLbO.js +0 -3
- package/dist/assets/arrow-left-BOCJyLbQ.js +0 -1
- package/dist/assets/book-open-Bd2Xbrrc.js +0 -1
- package/dist/assets/channels-list-page-moJkpxtU.js +0 -8
- package/dist/assets/chat-page-CO27cl4v.js +0 -105
- package/dist/assets/config-split-page-CsQ2rIdq.js +0 -1
- package/dist/assets/desktop-update-config-qa-SynOc.js +0 -1
- package/dist/assets/doc-browser-2ddUJCA0.js +0 -1
- package/dist/assets/doc-browser-BjHUczQb.js +0 -1
- package/dist/assets/es2015-BUIIKCNh.js +0 -41
- package/dist/assets/host-capabilities-9bB_998Z.js +0 -1
- package/dist/assets/index-CMNrRhnG.js +0 -101
- package/dist/assets/index-UTmTW1eU.css +0 -1
- package/dist/assets/key-round-D3vD9dj7.js +0 -1
- package/dist/assets/loader-circle-DV9TSRns.js +0 -1
- package/dist/assets/mcp-marketplace-page-CS5Lh3oA.js +0 -1
- package/dist/assets/mcp-marketplace-page-DEOMcWb0.js +0 -40
- package/dist/assets/model-config-page-BSc4o7pb.js +0 -1
- package/dist/assets/notice-card-qqlbsOoR.js +0 -1
- package/dist/assets/plus-Bf9qhPDO.js +0 -1
- package/dist/assets/popover-BnmPOXe3.js +0 -1
- package/dist/assets/provider-scoped-model-input-Ca56s475.js +0 -1
- package/dist/assets/providers-config-page-D8Kf4U3u.js +0 -1
- package/dist/assets/refresh-cw-Bmx4wc9P.js +0 -1
- package/dist/assets/remote-DNMEy_c4.js +0 -1
- package/dist/assets/rotate-cw-CL0sVBel.js +0 -1
- package/dist/assets/runtime-config-page-CUFtKr0U.js +0 -1
- package/dist/assets/search-D7L-TCH-.js +0 -1
- package/dist/assets/search-config-page-CA3RVAef.js +0 -1
- package/dist/assets/secrets-config-page-95yaH1fa.js +0 -3
- package/dist/assets/status-dot-Dm4h-bjn.js +0 -1
- package/dist/assets/tabs-CJvw5Lqp.js +0 -1
- package/dist/assets/tooltip-Bxzi6aDL.js +0 -1
- package/dist/assets/trash-2-CSfX-BvU.js +0 -1
- package/dist/assets/use-config-TzwzTgg0.js +0 -1
- package/dist/assets/x-fkIWvi07.js +0 -1
- package/src/features/chat/components/__tests__/chat-welcome.test.tsx +0 -45
- package/src/features/chat/components/chat-welcome.tsx +0 -102
- package/src/features/chat/features/input/hooks/__tests__/use-chat-input-bar-controller.test.tsx +0 -152
- package/src/features/chat/features/input/hooks/use-chat-input-bar-controller.ts +0 -142
- /package/dist/assets/{config-hints-Cl2XAhzV.js → config-hints-CTqBnCDp.js} +0 -0
|
@@ -24,16 +24,17 @@ export function buildRawPreviewBlock(params: {
|
|
|
24
24
|
oldStartLine?: number | null;
|
|
25
25
|
newStartLine?: number | null;
|
|
26
26
|
}): ParsedBlock | null {
|
|
27
|
-
const
|
|
27
|
+
const { newStartLine: rawNewStartLine, oldStartLine: rawOldStartLine, operation, path, text } = params;
|
|
28
|
+
const previewText = text.trim();
|
|
28
29
|
if (!previewText) {
|
|
29
30
|
return null;
|
|
30
31
|
}
|
|
31
32
|
const previewKind =
|
|
32
|
-
|
|
33
|
+
operation?.trim().toLowerCase() === "write" ? "add" : "context";
|
|
33
34
|
const oldStartLine =
|
|
34
|
-
typeof
|
|
35
|
+
typeof rawOldStartLine === "number" ? rawOldStartLine : 1;
|
|
35
36
|
const newStartLine =
|
|
36
|
-
typeof
|
|
37
|
+
typeof rawNewStartLine === "number" ? rawNewStartLine : 1;
|
|
37
38
|
const lines = buildPreviewLines({
|
|
38
39
|
text: previewText,
|
|
39
40
|
kind: previewKind,
|
|
@@ -41,10 +42,10 @@ export function buildRawPreviewBlock(params: {
|
|
|
41
42
|
newStartLine,
|
|
42
43
|
});
|
|
43
44
|
return {
|
|
44
|
-
path
|
|
45
|
+
path,
|
|
45
46
|
display: "preview",
|
|
46
47
|
caption: buildCaption({
|
|
47
|
-
operation
|
|
48
|
+
operation,
|
|
48
49
|
lines,
|
|
49
50
|
}),
|
|
50
51
|
lines,
|
|
@@ -62,10 +63,11 @@ export function buildFullReplaceBlock(params: {
|
|
|
62
63
|
oldStartLine?: number | null;
|
|
63
64
|
newStartLine?: number | null;
|
|
64
65
|
}): ParsedBlock | null {
|
|
66
|
+
const { afterText, beforeText, operation, path } = params;
|
|
65
67
|
const { oldStartLine, newStartLine } = readDefaultDiffStartLines(params);
|
|
66
68
|
const lines = buildLineDiff({
|
|
67
|
-
beforeText:
|
|
68
|
-
afterText:
|
|
69
|
+
beforeText: beforeText ?? "",
|
|
70
|
+
afterText: afterText ?? "",
|
|
69
71
|
oldStartLine,
|
|
70
72
|
newStartLine,
|
|
71
73
|
});
|
|
@@ -74,16 +76,16 @@ export function buildFullReplaceBlock(params: {
|
|
|
74
76
|
return null;
|
|
75
77
|
}
|
|
76
78
|
return {
|
|
77
|
-
path
|
|
79
|
+
path,
|
|
78
80
|
display: "diff",
|
|
79
81
|
caption: buildCaption({
|
|
80
|
-
operation
|
|
82
|
+
operation,
|
|
81
83
|
lines,
|
|
82
84
|
}),
|
|
83
85
|
lines: limited.lines,
|
|
84
86
|
...(limited.truncated ? { fullLines: lines } : {}),
|
|
85
|
-
...(
|
|
86
|
-
...(
|
|
87
|
+
...(beforeText != null ? { beforeText } : {}),
|
|
88
|
+
...(afterText != null ? { afterText } : {}),
|
|
87
89
|
...(typeof oldStartLine === "number" ? { oldStartLine } : {}),
|
|
88
90
|
...(typeof newStartLine === "number" ? { newStartLine } : {}),
|
|
89
91
|
truncated: limited.truncated,
|
|
@@ -95,23 +97,24 @@ function updateApplyPatchCursor(params: {
|
|
|
95
97
|
flushCurrent: () => void;
|
|
96
98
|
setCurrent: (path: string, operation: string) => void;
|
|
97
99
|
}): boolean {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
const { flushCurrent, line, setCurrent } = params;
|
|
101
|
+
if (line.startsWith("*** Update File: ")) {
|
|
102
|
+
flushCurrent();
|
|
103
|
+
setCurrent(
|
|
104
|
+
line.slice("*** Update File: ".length).trim(),
|
|
102
105
|
"update",
|
|
103
106
|
);
|
|
104
107
|
return true;
|
|
105
108
|
}
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
if (line.startsWith("*** Add File: ")) {
|
|
110
|
+
flushCurrent();
|
|
111
|
+
setCurrent(line.slice("*** Add File: ".length).trim(), "add");
|
|
109
112
|
return true;
|
|
110
113
|
}
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
if (line.startsWith("*** Delete File: ")) {
|
|
115
|
+
flushCurrent();
|
|
116
|
+
setCurrent(
|
|
117
|
+
line.slice("*** Delete File: ".length).trim(),
|
|
115
118
|
"delete",
|
|
116
119
|
);
|
|
117
120
|
return true;
|
|
@@ -128,18 +131,18 @@ function appendPatchLine(params: {
|
|
|
128
131
|
oldLineNumber?: number;
|
|
129
132
|
newLineNumber?: number;
|
|
130
133
|
} {
|
|
131
|
-
const { currentLines, line } = params;
|
|
134
|
+
const { currentLines, line, newLineNumber, oldLineNumber } = params;
|
|
132
135
|
if (line.startsWith("+")) {
|
|
133
136
|
currentLines.push(
|
|
134
137
|
createLine({
|
|
135
138
|
kind: "add",
|
|
136
139
|
text: line.slice(1),
|
|
137
|
-
newLineNumber
|
|
140
|
+
newLineNumber,
|
|
138
141
|
}),
|
|
139
142
|
);
|
|
140
143
|
return {
|
|
141
|
-
oldLineNumber
|
|
142
|
-
newLineNumber: incrementLineNumber(
|
|
144
|
+
oldLineNumber,
|
|
145
|
+
newLineNumber: incrementLineNumber(newLineNumber),
|
|
143
146
|
};
|
|
144
147
|
}
|
|
145
148
|
if (line.startsWith("-")) {
|
|
@@ -147,12 +150,12 @@ function appendPatchLine(params: {
|
|
|
147
150
|
createLine({
|
|
148
151
|
kind: "remove",
|
|
149
152
|
text: line.slice(1),
|
|
150
|
-
oldLineNumber
|
|
153
|
+
oldLineNumber,
|
|
151
154
|
}),
|
|
152
155
|
);
|
|
153
156
|
return {
|
|
154
|
-
oldLineNumber: incrementLineNumber(
|
|
155
|
-
newLineNumber
|
|
157
|
+
oldLineNumber: incrementLineNumber(oldLineNumber),
|
|
158
|
+
newLineNumber,
|
|
156
159
|
};
|
|
157
160
|
}
|
|
158
161
|
if (line.startsWith(" ")) {
|
|
@@ -160,18 +163,18 @@ function appendPatchLine(params: {
|
|
|
160
163
|
createLine({
|
|
161
164
|
kind: "context",
|
|
162
165
|
text: line.slice(1),
|
|
163
|
-
oldLineNumber
|
|
164
|
-
newLineNumber
|
|
166
|
+
oldLineNumber,
|
|
167
|
+
newLineNumber,
|
|
165
168
|
}),
|
|
166
169
|
);
|
|
167
170
|
return {
|
|
168
|
-
oldLineNumber: incrementLineNumber(
|
|
169
|
-
newLineNumber: incrementLineNumber(
|
|
171
|
+
oldLineNumber: incrementLineNumber(oldLineNumber),
|
|
172
|
+
newLineNumber: incrementLineNumber(newLineNumber),
|
|
170
173
|
};
|
|
171
174
|
}
|
|
172
175
|
return {
|
|
173
|
-
oldLineNumber
|
|
174
|
-
newLineNumber
|
|
176
|
+
oldLineNumber,
|
|
177
|
+
newLineNumber,
|
|
175
178
|
};
|
|
176
179
|
}
|
|
177
180
|
|
|
@@ -19,14 +19,15 @@ export function createLine(params: {
|
|
|
19
19
|
oldLineNumber?: number;
|
|
20
20
|
newLineNumber?: number;
|
|
21
21
|
}): ChatFileOperationLineViewModel {
|
|
22
|
+
const { kind, newLineNumber, oldLineNumber, text } = params;
|
|
22
23
|
return {
|
|
23
|
-
kind
|
|
24
|
-
text
|
|
25
|
-
...(typeof
|
|
26
|
-
? { oldLineNumber
|
|
24
|
+
kind,
|
|
25
|
+
text,
|
|
26
|
+
...(typeof oldLineNumber === "number"
|
|
27
|
+
? { oldLineNumber }
|
|
27
28
|
: {}),
|
|
28
|
-
...(typeof
|
|
29
|
-
? { newLineNumber
|
|
29
|
+
...(typeof newLineNumber === "number"
|
|
30
|
+
? { newLineNumber }
|
|
30
31
|
: {}),
|
|
31
32
|
};
|
|
32
33
|
}
|
|
@@ -51,18 +52,19 @@ export function buildPreviewLines(params: {
|
|
|
51
52
|
oldStartLine: number;
|
|
52
53
|
newStartLine: number;
|
|
53
54
|
}): ChatFileOperationLineViewModel[] {
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
const { kind, newStartLine, oldStartLine, text } = params;
|
|
56
|
+
return splitLines(text).map((line, index) =>
|
|
57
|
+
kind === "add"
|
|
56
58
|
? createLine({
|
|
57
59
|
kind: "add",
|
|
58
60
|
text: line,
|
|
59
|
-
newLineNumber:
|
|
61
|
+
newLineNumber: newStartLine + index,
|
|
60
62
|
})
|
|
61
63
|
: createLine({
|
|
62
64
|
kind: "context",
|
|
63
65
|
text: line,
|
|
64
|
-
oldLineNumber:
|
|
65
|
-
newLineNumber:
|
|
66
|
+
oldLineNumber: oldStartLine + index,
|
|
67
|
+
newLineNumber: newStartLine + index,
|
|
66
68
|
}),
|
|
67
69
|
);
|
|
68
70
|
}
|
|
@@ -73,10 +75,11 @@ function buildFallbackDiffLines(params: {
|
|
|
73
75
|
oldStartLine?: number;
|
|
74
76
|
newStartLine?: number;
|
|
75
77
|
}): ChatFileOperationLineViewModel[] {
|
|
76
|
-
|
|
77
|
-
let
|
|
78
|
+
const { afterLines, beforeLines, newStartLine, oldStartLine } = params;
|
|
79
|
+
let oldLineNumber = oldStartLine;
|
|
80
|
+
let newLineNumber = newStartLine;
|
|
78
81
|
return [
|
|
79
|
-
...
|
|
82
|
+
...beforeLines.map((line) => {
|
|
80
83
|
const nextLine = createLine({
|
|
81
84
|
kind: "remove",
|
|
82
85
|
text: line,
|
|
@@ -85,7 +88,7 @@ function buildFallbackDiffLines(params: {
|
|
|
85
88
|
oldLineNumber = incrementLineNumber(oldLineNumber);
|
|
86
89
|
return nextLine;
|
|
87
90
|
}),
|
|
88
|
-
...
|
|
91
|
+
...afterLines.map((line) => {
|
|
89
92
|
const nextLine = createLine({
|
|
90
93
|
kind: "add",
|
|
91
94
|
text: line,
|
|
@@ -101,22 +104,23 @@ function buildLcsMatrix(params: {
|
|
|
101
104
|
beforeLines: string[];
|
|
102
105
|
afterLines: string[];
|
|
103
106
|
}): number[][] {
|
|
107
|
+
const { afterLines, beforeLines } = params;
|
|
104
108
|
const matrix: number[][] = Array.from(
|
|
105
|
-
{ length:
|
|
106
|
-
() => Array.from({ length:
|
|
109
|
+
{ length: beforeLines.length + 1 },
|
|
110
|
+
() => Array.from({ length: afterLines.length + 1 }, () => 0),
|
|
107
111
|
);
|
|
108
112
|
for (
|
|
109
|
-
let beforeIndex =
|
|
113
|
+
let beforeIndex = beforeLines.length - 1;
|
|
110
114
|
beforeIndex >= 0;
|
|
111
115
|
beforeIndex -= 1
|
|
112
116
|
) {
|
|
113
117
|
for (
|
|
114
|
-
let afterIndex =
|
|
118
|
+
let afterIndex = afterLines.length - 1;
|
|
115
119
|
afterIndex >= 0;
|
|
116
120
|
afterIndex -= 1
|
|
117
121
|
) {
|
|
118
122
|
matrix[beforeIndex]![afterIndex] =
|
|
119
|
-
|
|
123
|
+
beforeLines[beforeIndex] === afterLines[afterIndex]
|
|
120
124
|
? (matrix[beforeIndex + 1]![afterIndex + 1] ?? 0) + 1
|
|
121
125
|
: Math.max(
|
|
122
126
|
matrix[beforeIndex + 1]![afterIndex] ?? 0,
|
|
@@ -136,33 +140,36 @@ function appendRemainingDiffLines(params: {
|
|
|
136
140
|
oldLineNumber?: number;
|
|
137
141
|
newLineNumber?: number;
|
|
138
142
|
}): void {
|
|
143
|
+
const { afterIndex, afterLines, beforeIndex, beforeLines, lines, newLineNumber: initialNewLineNumber, oldLineNumber: initialOldLineNumber } = params;
|
|
144
|
+
let oldLineNumber = initialOldLineNumber;
|
|
145
|
+
let newLineNumber = initialNewLineNumber;
|
|
139
146
|
for (
|
|
140
|
-
let index =
|
|
141
|
-
index <
|
|
147
|
+
let index = beforeIndex;
|
|
148
|
+
index < beforeLines.length;
|
|
142
149
|
index += 1
|
|
143
150
|
) {
|
|
144
|
-
|
|
151
|
+
lines.push(
|
|
145
152
|
createLine({
|
|
146
153
|
kind: "remove",
|
|
147
|
-
text:
|
|
148
|
-
oldLineNumber
|
|
154
|
+
text: beforeLines[index] ?? "",
|
|
155
|
+
oldLineNumber,
|
|
149
156
|
}),
|
|
150
157
|
);
|
|
151
|
-
|
|
158
|
+
oldLineNumber = incrementLineNumber(oldLineNumber);
|
|
152
159
|
}
|
|
153
160
|
for (
|
|
154
|
-
let index =
|
|
155
|
-
index <
|
|
161
|
+
let index = afterIndex;
|
|
162
|
+
index < afterLines.length;
|
|
156
163
|
index += 1
|
|
157
164
|
) {
|
|
158
|
-
|
|
165
|
+
lines.push(
|
|
159
166
|
createLine({
|
|
160
167
|
kind: "add",
|
|
161
|
-
text:
|
|
162
|
-
newLineNumber
|
|
168
|
+
text: afterLines[index] ?? "",
|
|
169
|
+
newLineNumber,
|
|
163
170
|
}),
|
|
164
171
|
);
|
|
165
|
-
|
|
172
|
+
newLineNumber = incrementLineNumber(newLineNumber);
|
|
166
173
|
}
|
|
167
174
|
}
|
|
168
175
|
|
|
@@ -172,14 +179,15 @@ export function buildLineDiff(params: {
|
|
|
172
179
|
oldStartLine?: number;
|
|
173
180
|
newStartLine?: number;
|
|
174
181
|
}): ChatFileOperationLineViewModel[] {
|
|
175
|
-
const
|
|
176
|
-
const
|
|
182
|
+
const { afterText, beforeText, newStartLine, oldStartLine } = params;
|
|
183
|
+
const beforeLines = splitLines(beforeText);
|
|
184
|
+
const afterLines = splitLines(afterText);
|
|
177
185
|
if (beforeLines.length * afterLines.length > MAX_DIFF_MATRIX_CELLS) {
|
|
178
186
|
return buildFallbackDiffLines({
|
|
179
187
|
beforeLines,
|
|
180
188
|
afterLines,
|
|
181
|
-
oldStartLine
|
|
182
|
-
newStartLine
|
|
189
|
+
oldStartLine,
|
|
190
|
+
newStartLine,
|
|
183
191
|
});
|
|
184
192
|
}
|
|
185
193
|
|
|
@@ -190,8 +198,8 @@ export function buildLineDiff(params: {
|
|
|
190
198
|
const lines: ChatFileOperationLineViewModel[] = [];
|
|
191
199
|
let beforeIndex = 0;
|
|
192
200
|
let afterIndex = 0;
|
|
193
|
-
let oldLineNumber =
|
|
194
|
-
let newLineNumber =
|
|
201
|
+
let oldLineNumber = oldStartLine;
|
|
202
|
+
let newLineNumber = newStartLine;
|
|
195
203
|
while (beforeIndex < beforeLines.length && afterIndex < afterLines.length) {
|
|
196
204
|
if (beforeLines[beforeIndex] === afterLines[afterIndex]) {
|
|
197
205
|
lines.push(
|
|
@@ -20,10 +20,11 @@ export function buildCaption(params: {
|
|
|
20
20
|
operation?: string | null;
|
|
21
21
|
lines: ChatFileOperationLineViewModel[];
|
|
22
22
|
}): string | undefined {
|
|
23
|
-
const
|
|
24
|
-
const
|
|
23
|
+
const { lines, operation } = params;
|
|
24
|
+
const additions = lines.filter((line) => line.kind === "add").length;
|
|
25
|
+
const deletions = lines.filter((line) => line.kind === "remove").length;
|
|
25
26
|
const parts: string[] = [];
|
|
26
|
-
const normalizedOperation =
|
|
27
|
+
const normalizedOperation = operation?.trim().toLowerCase() ?? "";
|
|
27
28
|
if (normalizedOperation && normalizedOperation !== "update") {
|
|
28
29
|
parts.push(normalizedOperation);
|
|
29
30
|
}
|
|
@@ -46,20 +47,21 @@ export function readDefaultDiffStartLines(params: {
|
|
|
46
47
|
oldStartLine?: number;
|
|
47
48
|
newStartLine?: number;
|
|
48
49
|
} {
|
|
49
|
-
const
|
|
50
|
+
const { afterText, beforeText, newStartLine: rawNewStartLine, oldStartLine: rawOldStartLine, operation } = params;
|
|
51
|
+
const normalizedOperation = operation?.trim().toLowerCase() ?? "";
|
|
50
52
|
const oldStartLine =
|
|
51
|
-
typeof
|
|
52
|
-
?
|
|
53
|
+
typeof rawOldStartLine === "number"
|
|
54
|
+
? rawOldStartLine
|
|
53
55
|
: (normalizedOperation === "delete" ||
|
|
54
56
|
normalizedOperation === "remove") &&
|
|
55
|
-
|
|
57
|
+
beforeText != null
|
|
56
58
|
? 1
|
|
57
59
|
: undefined;
|
|
58
60
|
const newStartLine =
|
|
59
|
-
typeof
|
|
60
|
-
?
|
|
61
|
+
typeof rawNewStartLine === "number"
|
|
62
|
+
? rawNewStartLine
|
|
61
63
|
: (normalizedOperation === "write" || normalizedOperation === "add") &&
|
|
62
|
-
|
|
64
|
+
afterText != null
|
|
63
65
|
? 1
|
|
64
66
|
: undefined;
|
|
65
67
|
return { oldStartLine, newStartLine };
|
|
@@ -83,16 +85,17 @@ export function buildParsedPatchBlock(params: {
|
|
|
83
85
|
operation: string | null;
|
|
84
86
|
lines: ChatFileOperationLineViewModel[];
|
|
85
87
|
}): ParsedBlock {
|
|
86
|
-
const
|
|
88
|
+
const { lines, operation, path } = params;
|
|
89
|
+
const limited = limitLines(lines);
|
|
87
90
|
return {
|
|
88
|
-
path
|
|
91
|
+
path,
|
|
89
92
|
display: "diff",
|
|
90
93
|
caption: buildCaption({
|
|
91
|
-
operation
|
|
92
|
-
lines
|
|
94
|
+
operation,
|
|
95
|
+
lines,
|
|
93
96
|
}),
|
|
94
97
|
lines: limited.lines,
|
|
95
|
-
...(limited.truncated ? { fullLines:
|
|
98
|
+
...(limited.truncated ? { fullLines: lines } : {}),
|
|
96
99
|
truncated: limited.truncated,
|
|
97
100
|
};
|
|
98
101
|
}
|
|
@@ -6,13 +6,16 @@ import type { ConfigView, ProvidersView, ProviderTemplatesView } from '@/shared/
|
|
|
6
6
|
import type { ChatModelOption } from '@/features/chat/types/chat-input.types';
|
|
7
7
|
import { buildProviderModelCatalog, composeProviderModel, resolveModelThinkingCapability } from '@/shared/lib/provider-models';
|
|
8
8
|
|
|
9
|
-
function buildRuntimeDefaultModelOption(
|
|
9
|
+
function buildRuntimeDefaultModelOption(
|
|
10
|
+
label: string,
|
|
11
|
+
thinkingCapability?: ChatModelOption['thinkingCapability'],
|
|
12
|
+
): ChatModelOption {
|
|
10
13
|
return {
|
|
11
14
|
value: RUNTIME_DEFAULT_MODEL_VALUE,
|
|
12
15
|
modelLabel: label,
|
|
13
16
|
providerLabel: '',
|
|
14
17
|
isRuntimeDefault: true,
|
|
15
|
-
thinkingCapability: null,
|
|
18
|
+
thinkingCapability: thinkingCapability ?? null,
|
|
16
19
|
};
|
|
17
20
|
}
|
|
18
21
|
|
|
@@ -50,16 +53,21 @@ export function buildNcpChatProviderModelOptions(params: {
|
|
|
50
53
|
export function filterNcpChatModelOptionsBySessionType(params: {
|
|
51
54
|
modelOptions: ChatModelOption[];
|
|
52
55
|
modelSelectionMode?: RuntimeModelSelectionMode;
|
|
56
|
+
runtimeDefaultThinkingCapability?: ChatModelOption['thinkingCapability'];
|
|
53
57
|
runtimeDefaultModelLabel?: string;
|
|
54
58
|
supportedModels?: string[];
|
|
55
59
|
}): ChatModelOption[] {
|
|
56
60
|
const {
|
|
57
61
|
modelOptions,
|
|
58
62
|
modelSelectionMode,
|
|
63
|
+
runtimeDefaultThinkingCapability,
|
|
59
64
|
runtimeDefaultModelLabel = 'Runtime default',
|
|
60
65
|
supportedModels,
|
|
61
66
|
} = params;
|
|
62
|
-
const runtimeDefaultOption = buildRuntimeDefaultModelOption(
|
|
67
|
+
const runtimeDefaultOption = buildRuntimeDefaultModelOption(
|
|
68
|
+
runtimeDefaultModelLabel,
|
|
69
|
+
runtimeDefaultThinkingCapability,
|
|
70
|
+
);
|
|
63
71
|
if (modelSelectionMode === 'runtime-default') {
|
|
64
72
|
return [runtimeDefaultOption];
|
|
65
73
|
}
|
|
@@ -45,6 +45,7 @@ describe('ChatSessionHeaderActions', () => {
|
|
|
45
45
|
|
|
46
46
|
expect(screen.getByText('Set Project Directory')).toBeTruthy();
|
|
47
47
|
expect(screen.queryByText('Clear Project Directory')).toBeNull();
|
|
48
|
+
expect(screen.getByText('View Metadata')).toBeTruthy();
|
|
48
49
|
expect(screen.getByText('Delete Session')).toBeTruthy();
|
|
49
50
|
});
|
|
50
51
|
|
|
@@ -67,6 +68,32 @@ describe('ChatSessionHeaderActions', () => {
|
|
|
67
68
|
|
|
68
69
|
expect(screen.getByText('Set Project Directory')).toBeTruthy();
|
|
69
70
|
expect(screen.queryByText('Clear Project Directory')).toBeNull();
|
|
71
|
+
expect(screen.getByText('View Metadata')).toBeTruthy();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('opens the session metadata dialog from the more-actions menu', async () => {
|
|
75
|
+
const user = userEvent.setup();
|
|
76
|
+
|
|
77
|
+
render(
|
|
78
|
+
<ChatSessionHeaderActions
|
|
79
|
+
sessionKey="session-codex"
|
|
80
|
+
canDeleteSession
|
|
81
|
+
isDeletePending={false}
|
|
82
|
+
projectRoot={null}
|
|
83
|
+
metadata={{
|
|
84
|
+
codex_thread_id: 'thread-123',
|
|
85
|
+
runtime: 'codex',
|
|
86
|
+
}}
|
|
87
|
+
onDeleteSession={mocks.onDeleteSession}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
await user.click(screen.getByRole('button', { name: 'More actions' }));
|
|
92
|
+
await user.click(screen.getByRole('button', { name: 'View Metadata' }));
|
|
93
|
+
|
|
94
|
+
expect(screen.getByRole('dialog', { name: 'Session Metadata' })).toBeTruthy();
|
|
95
|
+
expect(screen.getByText(/codex_thread_id/)).toBeTruthy();
|
|
96
|
+
expect(screen.getByText(/thread-123/)).toBeTruthy();
|
|
70
97
|
});
|
|
71
98
|
|
|
72
99
|
it('shows a dedicated child-session entry button when the current session has child sessions', async () => {
|
|
@@ -2,6 +2,7 @@ import { render, screen, waitFor } from '@testing-library/react';
|
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
3
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
4
|
import { ChatSessionProjectBadge } from '@/features/chat/features/session/components/session-header/chat-session-project-badge';
|
|
5
|
+
import { createPopoverAvailableHeightLimit } from '@/shared/components/ui/popover';
|
|
5
6
|
|
|
6
7
|
const mocks = vi.hoisted(() => ({
|
|
7
8
|
updateSessionProject: vi.fn(),
|
|
@@ -15,6 +16,17 @@ vi.mock('@/features/chat/features/session/components/session-header/chat-session
|
|
|
15
16
|
ChatSessionProjectDialog: () => null,
|
|
16
17
|
}));
|
|
17
18
|
|
|
19
|
+
function renderProjectBadge() {
|
|
20
|
+
return render(
|
|
21
|
+
<ChatSessionProjectBadge
|
|
22
|
+
sessionKey="session-1"
|
|
23
|
+
projectName="project-alpha"
|
|
24
|
+
projectRoot="/tmp/project-alpha"
|
|
25
|
+
persistToServer
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
18
30
|
describe('ChatSessionProjectBadge', () => {
|
|
19
31
|
beforeEach(() => {
|
|
20
32
|
mocks.updateSessionProject.mockReset();
|
|
@@ -24,31 +36,26 @@ describe('ChatSessionProjectBadge', () => {
|
|
|
24
36
|
it('shows project actions inside the badge popover', async () => {
|
|
25
37
|
const user = userEvent.setup();
|
|
26
38
|
|
|
27
|
-
|
|
28
|
-
<ChatSessionProjectBadge
|
|
29
|
-
sessionKey="session-1"
|
|
30
|
-
projectName="project-alpha"
|
|
31
|
-
projectRoot="/tmp/project-alpha"
|
|
32
|
-
persistToServer
|
|
33
|
-
/>
|
|
34
|
-
);
|
|
39
|
+
renderProjectBadge();
|
|
35
40
|
|
|
36
41
|
await user.click(screen.getByRole('button', { name: 'Set Project Directory' }));
|
|
37
42
|
|
|
38
43
|
expect(screen.getAllByText('Set Project Directory').length).toBeGreaterThan(0);
|
|
39
44
|
expect(screen.getByText('Clear Project Directory')).toBeTruthy();
|
|
40
|
-
|
|
45
|
+
const projectRoot = screen.getByText('/tmp/project-alpha');
|
|
46
|
+
expect(projectRoot).toBeTruthy();
|
|
47
|
+
|
|
48
|
+
const boundedPopover = projectRoot.closest('[style*="max-height"]') as HTMLElement | null;
|
|
49
|
+
expect(boundedPopover?.style.maxHeight).toBe(
|
|
50
|
+
createPopoverAvailableHeightLimit('18rem')
|
|
51
|
+
);
|
|
52
|
+
expect(boundedPopover?.style.maxHeight).toContain('max(0px');
|
|
53
|
+
expect(boundedPopover?.style.maxHeight).toContain('100vh');
|
|
54
|
+
expect(boundedPopover?.style.maxHeight).toContain('2rem');
|
|
41
55
|
});
|
|
42
56
|
|
|
43
57
|
it('uses the neutral header tag styling instead of a highlighted accent color', () => {
|
|
44
|
-
|
|
45
|
-
<ChatSessionProjectBadge
|
|
46
|
-
sessionKey="session-1"
|
|
47
|
-
projectName="project-alpha"
|
|
48
|
-
projectRoot="/tmp/project-alpha"
|
|
49
|
-
persistToServer
|
|
50
|
-
/>
|
|
51
|
-
);
|
|
58
|
+
renderProjectBadge();
|
|
52
59
|
|
|
53
60
|
const trigger = screen.getByRole('button', { name: 'Set Project Directory' });
|
|
54
61
|
expect(trigger.className).toContain('border-gray-200');
|
|
@@ -59,14 +66,7 @@ describe('ChatSessionProjectBadge', () => {
|
|
|
59
66
|
it('clears the current project from the badge popover', async () => {
|
|
60
67
|
const user = userEvent.setup();
|
|
61
68
|
|
|
62
|
-
|
|
63
|
-
<ChatSessionProjectBadge
|
|
64
|
-
sessionKey="session-1"
|
|
65
|
-
projectName="project-alpha"
|
|
66
|
-
projectRoot="/tmp/project-alpha"
|
|
67
|
-
persistToServer
|
|
68
|
-
/>
|
|
69
|
-
);
|
|
69
|
+
renderProjectBadge();
|
|
70
70
|
|
|
71
71
|
await user.click(screen.getByRole('button', { name: 'Set Project Directory' }));
|
|
72
72
|
await user.click(screen.getByText('Clear Project Directory'));
|
package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
|
-
import { AlarmClock, FolderOpen, GitBranch, MoreVertical, Trash2 } from 'lucide-react';
|
|
2
|
+
import { AlarmClock, Braces, FolderOpen, GitBranch, MoreVertical, Trash2 } from 'lucide-react';
|
|
3
3
|
import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
|
|
4
4
|
import { Popover, PopoverContent, PopoverTrigger } from '@/shared/components/ui/popover';
|
|
5
5
|
import { useChatSessionProject } from '@/features/chat/features/session/hooks/use-chat-session-project';
|
|
6
6
|
import { ChatSessionHeaderMenuItem } from './chat-session-header-menu-item';
|
|
7
|
+
import { ChatSessionMetadataDialog } from './chat-session-metadata-dialog';
|
|
7
8
|
import { ChatSessionProjectDialog } from './chat-session-project-dialog';
|
|
8
9
|
import { t } from '@/shared/lib/i18n';
|
|
9
10
|
|
|
@@ -15,6 +16,7 @@ type ChatSessionHeaderActionsProps = {
|
|
|
15
16
|
canDeleteSession: boolean;
|
|
16
17
|
isDeletePending: boolean;
|
|
17
18
|
projectRoot?: string | null;
|
|
19
|
+
metadata?: Record<string, unknown> | null;
|
|
18
20
|
childSessionCount?: number;
|
|
19
21
|
sessionCronJobCount?: number;
|
|
20
22
|
onOpenChildSessions?: () => void;
|
|
@@ -27,6 +29,7 @@ export function ChatSessionHeaderActions({
|
|
|
27
29
|
canDeleteSession,
|
|
28
30
|
isDeletePending,
|
|
29
31
|
projectRoot,
|
|
32
|
+
metadata,
|
|
30
33
|
childSessionCount = 0,
|
|
31
34
|
sessionCronJobCount = 0,
|
|
32
35
|
onOpenChildSessions,
|
|
@@ -36,6 +39,7 @@ export function ChatSessionHeaderActions({
|
|
|
36
39
|
const updateSessionProject = useChatSessionProject();
|
|
37
40
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
38
41
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
42
|
+
const [isMetadataDialogOpen, setIsMetadataDialogOpen] = useState(false);
|
|
39
43
|
const [isProjectPending, setIsProjectPending] = useState(false);
|
|
40
44
|
const isBusy = isDeletePending || isProjectPending;
|
|
41
45
|
|
|
@@ -96,6 +100,15 @@ export function ChatSessionHeaderActions({
|
|
|
96
100
|
}}
|
|
97
101
|
disabled={isBusy}
|
|
98
102
|
/>
|
|
103
|
+
<ChatSessionHeaderMenuItem
|
|
104
|
+
icon={Braces}
|
|
105
|
+
label={t('chatSessionViewMetadata')}
|
|
106
|
+
onClick={() => {
|
|
107
|
+
setIsMenuOpen(false);
|
|
108
|
+
setIsMetadataDialogOpen(true);
|
|
109
|
+
}}
|
|
110
|
+
disabled={isBusy}
|
|
111
|
+
/>
|
|
99
112
|
<ChatSessionHeaderMenuItem
|
|
100
113
|
icon={Trash2}
|
|
101
114
|
label={t('chatDeleteSession')}
|
|
@@ -117,6 +130,11 @@ export function ChatSessionHeaderActions({
|
|
|
117
130
|
onOpenChange={setIsDialogOpen}
|
|
118
131
|
onSave={runProjectUpdate}
|
|
119
132
|
/>
|
|
133
|
+
<ChatSessionMetadataDialog
|
|
134
|
+
open={isMetadataDialogOpen}
|
|
135
|
+
metadata={metadata}
|
|
136
|
+
onOpenChange={setIsMetadataDialogOpen}
|
|
137
|
+
/>
|
|
120
138
|
</div>
|
|
121
139
|
);
|
|
122
140
|
}
|