Skip to content

Commit ef6e7be

Browse files
committed
fix: simplify content diff availability
1 parent 675fa12 commit ef6e7be

13 files changed

Lines changed: 89 additions & 123 deletions

File tree

chat2db-community-client/scripts/i18n-source-hashes.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"license.ts": "6aff8c38b1a7475264aa1e16e88d9b9731ecef112af70fe53edab449788ea788",
1717
"login.ts": "d6b15f2b4db713711c093108372027ad65899aec6dd963d3f954231a9ce5b890",
1818
"menu.ts": "1f9adabb7465ed545bdaa57fd2a0c10913e04979e710f65c6822f295c4d3e6ed",
19-
"monaco.ts": "ad710967f2cabee3264617e1d628f533e107bbd56f7ec0f7639c6e61e586c508",
19+
"monaco.ts": "2facdb8a37b221f9debbba699abe2ead36980cd314c0c33ae85bebdd44c1a69d",
2020
"notification.ts": "500751da2f02391622f074448eb46611fd41da2e5530d6c7d65f17a1382bd236",
2121
"plugin.ts": "01f15b6342cc5b29899ee4144d67b04bb4bc02c6bb10779806be322dc5e9a2bc",
2222
"price.ts": "26e35cb96368585f83a29adbb14e300da9b7f5278a4320063e81a1d1dd0adee9",
@@ -43,7 +43,7 @@
4343
"license.ts": "6aff8c38b1a7475264aa1e16e88d9b9731ecef112af70fe53edab449788ea788",
4444
"login.ts": "d6b15f2b4db713711c093108372027ad65899aec6dd963d3f954231a9ce5b890",
4545
"menu.ts": "1f9adabb7465ed545bdaa57fd2a0c10913e04979e710f65c6822f295c4d3e6ed",
46-
"monaco.ts": "ad710967f2cabee3264617e1d628f533e107bbd56f7ec0f7639c6e61e586c508",
46+
"monaco.ts": "2facdb8a37b221f9debbba699abe2ead36980cd314c0c33ae85bebdd44c1a69d",
4747
"notification.ts": "500751da2f02391622f074448eb46611fd41da2e5530d6c7d65f17a1382bd236",
4848
"plugin.ts": "01f15b6342cc5b29899ee4144d67b04bb4bc02c6bb10779806be322dc5e9a2bc",
4949
"price.ts": "26e35cb96368585f83a29adbb14e300da9b7f5278a4320063e81a1d1dd0adee9",

chat2db-community-client/src/components/SQLEditor/components/OperationLine/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ const OperationLine = ({
295295
className={styles.operatingButtonIcon}
296296
code="icon-switch-horizontal"
297297
size="sm"
298+
title={i18n('monaco.text.showDiff')}
298299
onClick={() => {
299300
action(SQLOptType.OPEN_CONTENT_DIFF);
300301
}}

chat2db-community-client/src/components/SQLEditor/editor/SQLEditorWithOperation/index.tsx

Lines changed: 16 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import React, {
66
useState,
77
useEffect,
88
CSSProperties,
9-
useMemo,
109
} from 'react';
1110
import { useStyles } from './style';
1211
import { OperationLine, MonacoEditorErrorTips } from '../../components';
@@ -53,10 +52,9 @@ import {
5352
} from '../../helper/databaseObjectTreeNode';
5453
import { treeConfig } from '@/blocks/NewTree/treeConfig';
5554
import {
56-
ContentDiffSurface,
55+
ContentDiffDenyReason,
5756
getContentDiffEligibility,
58-
guardContentDiffTexts,
59-
isContentDiffSurfaceEnabled,
57+
getContentDiffOpenBlockReason,
6058
} from '../../helper/contentDiffGuard';
6159

6260
interface ISQLEditorWithOperationProps {
@@ -150,8 +148,6 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
150148
const [contextTableIdentifier, setContextTableIdentifier] = useState<EditorTableIdentifier | null>(null);
151149
const [errorMessage, setErrorMessage] = useState<string | null>(null);
152150
const [hasEditorContent, setHasEditorContent] = useState<boolean>(!!defaultSQL?.trim());
153-
const [editorReady, setEditorReady] = useState(false);
154-
const [hasContentDiffChanges, setHasContentDiffChanges] = useState(false);
155151
const [routineExecutionModal, setRoutineExecutionModal] = useState({
156152
open: false,
157153
title: '',
@@ -172,43 +168,6 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
172168
});
173169
const sqlEditorRef = useRef<SQLEditorRef>(null);
174170
const routineExecutionEditorRef = useRef<SQLEditorRef>(null);
175-
const contentDiffEligibility = useMemo(
176-
() => getContentDiffEligibility({ editorType: type, dbInfo, readOnly: isReadOnly }),
177-
[
178-
dbInfo.consoleId,
179-
dbInfo.dataSourceId,
180-
dbInfo.databaseName,
181-
dbInfo.filePath,
182-
dbInfo.schemaName,
183-
dbInfo.status,
184-
dbInfo.tableName,
185-
dbInfo.viewName,
186-
(dbInfo as Record<string, unknown>).functionName,
187-
(dbInfo as Record<string, unknown>).procedureName,
188-
(dbInfo as Record<string, unknown>).triggerName,
189-
isReadOnly,
190-
type,
191-
],
192-
);
193-
const enableContentDiffHints = contentDiffEligibility.enabled;
194-
const refreshContentDiffChanges = useCallback((value?: string) => {
195-
if (!enableContentDiffHints) {
196-
setHasContentDiffChanges(false);
197-
return;
198-
}
199-
if (!editorReady || !sqlEditorRef.current) {
200-
setHasContentDiffChanges(false);
201-
return;
202-
}
203-
204-
const baseline = sqlEditorRef.current?.getContentDiffBaseline() ?? defaultSQL ?? '';
205-
const currentValue = value ?? sqlEditorRef.current?.getValue() ?? '';
206-
setHasContentDiffChanges(guardContentDiffTexts(baseline, currentValue).enabled);
207-
}, [defaultSQL, editorReady, enableContentDiffHints]);
208-
209-
useEffect(() => {
210-
refreshContentDiffChanges();
211-
}, [refreshContentDiffChanges]);
212171
const { consoleAiInputParams } = useWorkspaceStore((state) => {
213172
return {
214173
consoleAiInputParams: state.consoleAiInputParams,
@@ -323,7 +282,7 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
323282
}
324283
}, [active, consoleAiInputParams]);
325284

326-
const { saveConsole } = useSaveEditorData({
285+
const { saveConsole, hasSavedSqlRecord } = useSaveEditorData({
327286
editorRef: sqlEditorRef,
328287
isActive: active,
329288
boundInfo: dbInfo,
@@ -333,6 +292,12 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
333292
type,
334293
});
335294

295+
const { enabled: enableContentDiffHints, sourceId: contentDiffSourceId } = getContentDiffEligibility({
296+
editorType: type,
297+
dbInfo,
298+
savedSqlRecord: hasSavedSqlRecord,
299+
});
300+
336301
const handleAction = (actionType: SQLOptType, params?: any) => {
337302
if (isReadOnly && !READONLY_ALLOWED_ACTIONS.has(actionType)) {
338303
return;
@@ -564,7 +529,6 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
564529
const sql = await reloadSQL();
565530
setValue(sql || '', 'reset');
566531
sqlEditorRef.current?.resetContentDiffBaseline(sql || '');
567-
setHasContentDiffChanges(false);
568532
if (!options?.silent) {
569533
staticMessage.success(i18n('workspace.routine.tips.refreshSuccess'));
570534
}
@@ -577,7 +541,6 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
577541
const baseline = sqlEditorRef.current?.getContentDiffBaseline() ?? '';
578542
setValue(baseline, 'reset');
579543
sqlEditorRef.current?.resetContentDiffBaseline(baseline);
580-
setHasContentDiffChanges(false);
581544
staticMessage.success(i18n('workspace.routine.tips.revertSuccess'));
582545
};
583546

@@ -920,7 +883,6 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
920883
});
921884
try {
922885
sqlEditorRef.current?.resetContentDiffBaseline(fileContent);
923-
setHasContentDiffChanges(false);
924886
} catch {
925887
// Content diff is only a hint and must not affect file saving.
926888
}
@@ -938,20 +900,19 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
938900

939901
const handleOpenContentDiff = useCallback(() => {
940902
try {
941-
const eligibility = getContentDiffEligibility({ editorType: type, dbInfo, readOnly: isReadOnly });
942-
if (!eligibility.enabled || !isContentDiffSurfaceEnabled(ContentDiffSurface.DiffTab)) {
903+
if (!enableContentDiffHints) {
943904
return;
944905
}
945906

946907
const originalText = sqlEditorRef.current?.getContentDiffBaseline() ?? '';
947908
const modifiedText = sqlEditorRef.current?.getValue() ?? '';
948-
const guard = guardContentDiffTexts(originalText, modifiedText);
949-
if (!guard.enabled) {
909+
if (getContentDiffOpenBlockReason(originalText, modifiedText) === ContentDiffDenyReason.TextTooLarge) {
910+
staticMessage.warning(i18n('monaco.text.diffContentTooLarge'));
950911
return;
951912
}
952913

953914
const sourceId =
954-
eligibility.sourceId || String(id || dbInfo.consoleId || workspaceTabsTitle || sqlFileName || 'editor');
915+
contentDiffSourceId || String(id || dbInfo.consoleId || workspaceTabsTitle || sqlFileName || 'editor');
955916
const tabId = `${WorkspaceTabType.ContentDiff}:${sourceId}`;
956917
const title = `${getContentDiffSourceTitle({ workspaceTabsTitle, sqlFileName, dbInfo })}@`;
957918
const tab = {
@@ -978,7 +939,7 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
978939
} catch {
979940
// Content diff is only a hint and must not affect editor workflows.
980941
}
981-
}, [dbInfo, id, sqlFileName, workspaceTabsTitle]);
942+
}, [contentDiffSourceId, dbInfo, enableContentDiffHints, id, sqlFileName, workspaceTabsTitle]);
982943

983944
const handleFormat = async () => {
984945
const sql = sqlEditorRef.current?.getValue() || '';
@@ -1026,11 +987,7 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
1026987
hasEditorContent={hasEditorContent}
1027988
isConsole={isConsole}
1028989
setDBInfo={setDBInfo}
1029-
contentDiffEnabled={
1030-
enableContentDiffHints &&
1031-
hasContentDiffChanges &&
1032-
isContentDiffSurfaceEnabled(ContentDiffSurface.Toolbar)
1033-
}
990+
contentDiffEnabled={enableContentDiffHints}
1034991
action={handleAction}
1035992
/>
1036993
)}
@@ -1045,13 +1002,8 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
10451002
readOnly={isReadOnly}
10461003
action={handleAction}
10471004
enableContentDiffHints={enableContentDiffHints}
1048-
onReady={() => {
1049-
setEditorReady(true);
1050-
refreshContentDiffChanges();
1051-
}}
10521005
onChange={(value) => {
10531006
setHasEditorContent(!!value?.trim());
1054-
refreshContentDiffChanges(value);
10551007
}}
10561008
contextMenuInfo={contextMenuInfo}
10571009
onTableIdentifierContextChange={setContextTableIdentifier}
@@ -1066,11 +1018,7 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
10661018
config={contextMenuInfo}
10671019
canEditTable={!!contextTableIdentifier}
10681020
sqlActionEnabled={sqlActionEnabled}
1069-
contentDiffEnabled={
1070-
enableContentDiffHints &&
1071-
hasContentDiffChanges &&
1072-
isContentDiffSurfaceEnabled(ContentDiffSurface.ContextMenu)
1073-
}
1021+
contentDiffEnabled={enableContentDiffHints}
10741022
onClick={handleAction}
10751023
onCloseContextMenu={() => setContextMenuInfo(contextMenuDefaultConfig)}
10761024
/>

chat2db-community-client/src/components/SQLEditor/helper/contentDiffGuard.test.ts

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { ConsoleStatus } from '@/constants/common';
21
import { WorkspaceTabType } from '@/constants/workspace';
32
import {
43
ContentDiffDenyReason,
54
ContentDiffSourceKind,
65
getContentDiffDecorationCount,
76
getContentDiffEligibility,
7+
getContentDiffOpenBlockReason,
88
guardContentDiffTexts,
99
isContentDiffHunkBudgetExceeded,
1010
} from './contentDiffGuard';
@@ -26,7 +26,6 @@ function assert(condition: boolean, message: string) {
2626
assertEqual(
2727
getContentDiffEligibility({
2828
editorType: WorkspaceTabType.VIEW,
29-
readOnly: false,
3029
dbInfo: {
3130
dataSourceId: 1,
3231
databaseName: 'app',
@@ -41,10 +40,9 @@ assertEqual(
4140
assertEqual(
4241
getContentDiffEligibility({
4342
editorType: WorkspaceTabType.CONSOLE,
44-
readOnly: false,
43+
savedSqlRecord: true,
4544
dbInfo: {
4645
consoleId: 12,
47-
status: ConsoleStatus.RELEASE,
4846
},
4947
}),
5048
{
@@ -58,7 +56,6 @@ assertEqual(
5856
assertEqual(
5957
getContentDiffEligibility({
6058
editorType: WorkspaceTabType.LocalSQLFile,
61-
readOnly: false,
6259
dbInfo: {
6360
filePath: '/tmp/a.sql',
6461
},
@@ -74,22 +71,21 @@ assertEqual(
7471
assertEqual(
7572
getContentDiffEligibility({
7673
editorType: WorkspaceTabType.CONSOLE,
77-
readOnly: false,
74+
savedSqlRecord: false,
7875
dbInfo: {
79-
status: ConsoleStatus.DRAFT,
76+
status: 'DRAFT',
8077
},
8178
}).reason,
8279
ContentDiffDenyReason.UnsavedSQL,
83-
'deny unsaved sql record before status check',
80+
'deny console without a stable id',
8481
);
8582

8683
assertEqual(
8784
getContentDiffEligibility({
8885
editorType: WorkspaceTabType.CONSOLE,
89-
readOnly: false,
86+
savedSqlRecord: true,
9087
dbInfo: {
9188
consoleId: 'chat2db_temporary_1',
92-
status: ConsoleStatus.RELEASE,
9389
},
9490
}).reason,
9591
ContentDiffDenyReason.UnsavedSQL,
@@ -99,39 +95,43 @@ assertEqual(
9995
assertEqual(
10096
getContentDiffEligibility({
10197
editorType: WorkspaceTabType.CONSOLE,
102-
readOnly: false,
98+
savedSqlRecord: true,
10399
dbInfo: {
104100
consoleId: 12,
105-
status: ConsoleStatus.DRAFT,
101+
status: 'DRAFT',
106102
},
107-
}).reason,
108-
ContentDiffDenyReason.UnsupportedStatus,
109-
'deny draft saved sql record',
103+
}),
104+
{
105+
enabled: true,
106+
sourceKind: ContentDiffSourceKind.SavedSQL,
107+
sourceId: 'console:12',
108+
},
109+
'allow draft saved sql record',
110110
);
111111

112112
assertEqual(
113113
getContentDiffEligibility({
114-
editorType: WorkspaceTabType.FUNCTION,
115-
readOnly: false,
114+
editorType: WorkspaceTabType.CONSOLE,
115+
savedSqlRecord: false,
116116
dbInfo: {
117-
dataSourceId: 1,
118-
databaseName: 'app',
117+
consoleId: 12,
118+
status: 'DRAFT',
119119
},
120120
}).reason,
121-
ContentDiffDenyReason.MissingSource,
122-
'deny ddl without object name',
121+
ContentDiffDenyReason.UnsavedSQL,
122+
'deny ordinary console even when it has a persisted id',
123123
);
124124

125125
assertEqual(
126126
getContentDiffEligibility({
127-
editorType: WorkspaceTabType.VIEW,
128-
readOnly: true,
127+
editorType: WorkspaceTabType.FUNCTION,
129128
dbInfo: {
130-
viewName: 'v_user',
129+
dataSourceId: 1,
130+
databaseName: 'app',
131131
},
132132
}).reason,
133-
ContentDiffDenyReason.ReadOnly,
134-
'deny read only editor',
133+
ContentDiffDenyReason.MissingSource,
134+
'deny ddl without object name',
135135
);
136136

137137
assertEqual(
@@ -148,6 +148,18 @@ assertEqual(
148148
'deny large baseline',
149149
);
150150

151+
assertEqual(
152+
getContentDiffOpenBlockReason('select 1', 'select 1'),
153+
undefined,
154+
'allow opening unchanged content',
155+
);
156+
157+
assertEqual(
158+
getContentDiffOpenBlockReason('a'.repeat(200001), 'b'),
159+
ContentDiffDenyReason.TextTooLarge,
160+
'block opening oversized content',
161+
);
162+
151163
assertEqual(
152164
getContentDiffDecorationCount([
153165
{

0 commit comments

Comments
 (0)