Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions chat2db-community-client/scripts/i18n-source-hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"es-ES": {
"ai.ts": "391a6e14c58d8401bf3bc245eca5bdd4b66efd8225a877bfbbcae01a1c1c019a",
"chat.ts": "0cbe009eacbaa95a9a29bbc69588cb547e90b563667c53edec3e54ee64f5667b",
"common.ts": "1f70d1ba81aecbbd985a9dd9d1ae8b18ddfb3d209982a2ca17fbe3e4bf883a1f",
"common.ts": "8796e1084e494aac89a887dbd2546ec08e3ecbf0bbf22dbe0b342280d6702182",
"connection.ts": "41d07fd10c9550ae51995620cc998de5e99add35edb31c2bb592864c76c13688",
"dashboard.ts": "b217bbe260c7674d4efad1dd1b61136653858884f5b9b2134cfdf7d1de5a44ee",
"editTable.ts": "0f7a808f50053cd52b183d156bb4fd46bb125b8058f8774deb61c7f02894a350",
Expand All @@ -27,12 +27,12 @@
"stream.ts": "8418dd25b0fd54b2ef2b15a2573edf0a4876efb4e69936ff82a157ea5cf42be4",
"team.ts": "eb1fb03bdfeb93169ef1d2e347deb5b95071c10c8c93c35cfe2cb5b6606779ea",
"userGuide.ts": "0103ba35af95a3a0ff7a414130b68a7dd5f5f8196e59cd951631ac2090cb04fe",
"workspace.ts": "846c4ea2acd392fa026473cf216bfaf3f62c1a4355be872efa939aa199468c8d"
"workspace.ts": "df144283a0a2d8426f8c465d90a27ecd4b6194e01cee74a427a1e9aa983cc7ca"
},
"ko-KR": {
"ai.ts": "391a6e14c58d8401bf3bc245eca5bdd4b66efd8225a877bfbbcae01a1c1c019a",
"chat.ts": "0cbe009eacbaa95a9a29bbc69588cb547e90b563667c53edec3e54ee64f5667b",
"common.ts": "1f70d1ba81aecbbd985a9dd9d1ae8b18ddfb3d209982a2ca17fbe3e4bf883a1f",
"common.ts": "8796e1084e494aac89a887dbd2546ec08e3ecbf0bbf22dbe0b342280d6702182",
"connection.ts": "41d07fd10c9550ae51995620cc998de5e99add35edb31c2bb592864c76c13688",
"dashboard.ts": "b217bbe260c7674d4efad1dd1b61136653858884f5b9b2134cfdf7d1de5a44ee",
"editTable.ts": "0f7a808f50053cd52b183d156bb4fd46bb125b8058f8774deb61c7f02894a350",
Expand All @@ -54,7 +54,7 @@
"stream.ts": "8418dd25b0fd54b2ef2b15a2573edf0a4876efb4e69936ff82a157ea5cf42be4",
"team.ts": "eb1fb03bdfeb93169ef1d2e347deb5b95071c10c8c93c35cfe2cb5b6606779ea",
"userGuide.ts": "0103ba35af95a3a0ff7a414130b68a7dd5f5f8196e59cd951631ac2090cb04fe",
"workspace.ts": "846c4ea2acd392fa026473cf216bfaf3f62c1a4355be872efa939aa199468c8d"
"workspace.ts": "df144283a0a2d8426f8c465d90a27ecd4b6194e01cee74a427a1e9aa983cc7ca"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const createInitialData = () => {
sqlDatetimeSub: null,
charOctetLength: null,
ordinalPosition: null,
nullable: null,
nullable: NullableType.Null,
generatedColumn: null,
charSetName: null,
collationName: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import sqlService from '@/service/sql';
import _ from 'lodash';
import EditorChartModal, { EditChartModalRef } from '@/blocks/BI/ChartCardBox/EditorChartModal';
import DingChartModal, { DingChartModalRef } from '@/blocks/BI/ChartCardBox/DingChartModal';
import ChartNoAxesCombined from '@/components/LucideIcons/ChartNoAxesCombined';
import { useZoerStore } from '@/store/zoer';
import { useGlobalStore } from '@/store/global';

Expand Down Expand Up @@ -214,7 +215,7 @@ const ResultSetToolbar = forwardRef((props: IProps, ref: ForwardedRef<ResultSetT
}}
size="sm"
className={styles.createChartIcon}
code="icon-combo-chart"
icon={ChartNoAxesCombined}
/>
<EditorChartModal
submitEditorChartCallback={(data) => {
Expand Down
9 changes: 1 addition & 8 deletions chat2db-community-client/src/blocks/SearchResult/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
} from 'react';
import classnames from 'classnames';
import CustomTabs, { ITabItem } from '@/components/Tabs';
import Iconfont from '@/components/Iconfont';
import { IManageResultData } from '@/typings';
import SearchResultItem from './components/SearchResultItem';
import Abstract from '@/components/Abstract';
Expand Down Expand Up @@ -176,13 +175,7 @@ const SearchResult = forwardRef((props: IProps, ref: ForwardedRef<ISearchResultR
const tabsListRes =
newResultDataList?.map((queryResultData, index) => {
return {
prefixIcon: (
<Iconfont
key={index}
className={classnames(styles[queryResultData.success ? 'successIcon' : 'failIcon'], styles.statusIcon)}
code={queryResultData.success ? '\ue605' : '\ue87c'}
/>
),
prefixIcon: <IconfontSvg key={index} className={styles.resultTabIcon} size="sm" code="icon-table" />,
popover: (
<SQLPreview
source="search-result-tab-popover"
Expand Down
12 changes: 3 additions & 9 deletions chat2db-community-client/src/blocks/SearchResult/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,9 @@ export const useStyles = createStyles(({ css, token }) => {
font-size: 16px;
margin-right: 4px;
`,
statusIcon: css`
margin-right: 6px;
font-size: 12px;
`,
successIcon: css`
color: ${token.colorPrimary};
`,
failIcon: css`
color: ${token.colorError};
resultTabIcon: css`
margin-right: 4px;
color: inherit;
`,
tableIndex: css`
width: 50px;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { createLucideIcon } from 'lucide-react';

// Backport the official Lucide icon; the direct 0.356 dependency predates this export.
const ChartNoAxesCombined = createLucideIcon('ChartNoAxesCombined', [
['path', { d: 'M12 16v5', key: 'zza2cw' }],
['path', { d: 'M16 14v7', key: '1g90b9' }],
['path', { d: 'M20 10v11', key: '1iqoj0' }],
['path', { d: 'm22 3-8.646 8.646a.5.5 0 0 1-.708 0L9.354 8.354a.5.5 0 0 0-.707 0L2 15', key: '1fw8x9' }],
['path', { d: 'M4 18v3', key: '1yp0dc' }],
['path', { d: 'M8 14v7', key: 'n3cwzv' }],
]);

export default ChartNoAxesCombined;
31 changes: 26 additions & 5 deletions chat2db-community-client/src/components/Output/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useWorkspaceStore } from '@/store/workspace';
import { copyToClipboard, getTemporaryId } from '@/utils';
import { useTreeStore } from '@/store/tree';
import { TreeNodeData } from '@/typings';
import { SquareArrowOutUpRight } from 'lucide-react';

interface IProps {
className?: string;
Expand Down Expand Up @@ -150,10 +151,10 @@ export default memo<IProps>((props) => {
getHistoryList();
}, [getHistoryList]);

const openHistoryTab = useCallback(
async (item: IDatasource) => {
const openHistoryConsole = useCallback(
async (item: IDatasource, readOnly: boolean) => {
const detail = await getFullHistoryRecord(item);
const tabId = getTemporaryId(`execution-log-${item.id || Date.now()}`);
const tabId = getTemporaryId(`${readOnly ? 'execution-log' : 'execution-log-copy'}-${item.id || Date.now()}`);
const sourceInfo =
dataSourceInfoMap[getHistorySourceKey(detail)] || dataSourceInfoMap[getHistorySourceKey(item)];
const cachedSourceName =
Expand All @@ -167,7 +168,7 @@ export default memo<IProps>((props) => {
type: WorkspaceTabType.CONSOLE,
title,
uniqueData: {
consoleId: tabId,
consoleId: readOnly ? tabId : undefined,
dataSourceId: detail.dataSourceId || undefined,
dataSourceName: dataSourceName === '-' ? undefined : dataSourceName,
databaseType: detail.type || sourceInfo?.extraParams?.databaseType || undefined,
Expand All @@ -177,13 +178,26 @@ export default memo<IProps>((props) => {
ddl: detail.ddl || '',
connectable: detail.connectable ?? undefined,
popoverContent,
readOnly: true,
readOnly,
},
});
},
[addWorkspaceTab, dataSourceInfoMap, dataSourceNameMap, getFullHistoryRecord],
);

const openHistoryTab = useCallback(
(item: IDatasource) => openHistoryConsole(item, true),
[openHistoryConsole],
);

const openEditableHistoryTab = useCallback(
(event: React.MouseEvent, item: IDatasource) => {
event.stopPropagation();
return openHistoryConsole(item, false);
},
[openHistoryConsole],
);

const copyHistorySql = useCallback(
async (event: React.MouseEvent, item: IDatasource) => {
event.stopPropagation();
Expand Down Expand Up @@ -280,6 +294,13 @@ export default memo<IProps>((props) => {
</div>
</div>
<div className={classnames(styles.recordActions, 'output-record-actions')}>
<IconButton
className={styles.actionButton}
icon={SquareArrowOutUpRight}
size="sm"
title={i18n('common.button.openInNewConsole')}
onClick={(event) => openEditableHistoryTab(event, item)}
/>
<IconButton
className={styles.actionButton}
code="icon-copy"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const useStyles = createStyles(({ css, token }, { inputNumberWidth }: { i
cursor: pointer;
margin-left: 10px;
display: flex;
align-items: center;
gap: 4px;
&:hover {
color: ${token.colorPrimaryText};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Form, Input, Modal } from 'antd';
import i18n from '@/i18n';
import { normalizeSavedConsoleName } from '../../helper/savedConsoleName';

interface InitialSaveNameModalProps {
open: boolean;
name: string;
loading: boolean;
onNameChange: (name: string) => void;
onConfirm: () => void;
onCancel: () => void;
}

const InitialSaveNameModal = ({
open,
name,
loading,
onNameChange,
onConfirm,
onCancel,
}: InitialSaveNameModalProps) => {
const valid = !!normalizeSavedConsoleName(name);

return (
<Modal
open={open}
title={i18n('workspace.savedConsole.initialSaveTitle')}
width={420}
okText={i18n('common.button.confirm')}
cancelText={i18n('common.button.cancel')}
confirmLoading={loading}
okButtonProps={{ disabled: !valid }}
cancelButtonProps={{ disabled: loading }}
closable={!loading}
maskClosable={false}
destroyOnClose
onOk={onConfirm}
onCancel={onCancel}
>
<Form layout="vertical" requiredMark={false}>
<Form.Item
label={i18n('common.text.name')}
required
validateStatus={valid ? undefined : 'error'}
help={valid ? undefined : i18n('common.form.error.required')}
>
<Input
value={name}
placeholder={i18n('workspace.savedConsole.namePlaceholder')}
autoFocus
disabled={loading}
onFocus={(event) => event.currentTarget.select()}
onChange={(event) => onNameChange(event.target.value)}
onPressEnter={() => {
if (valid && !loading) {
onConfirm();
}
}}
/>
</Form.Item>
</Form>
</Modal>
);
};

export default InitialSaveNameModal;
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useStyles } from './style';
import { OperationLine, MonacoEditorErrorTips } from '../../components';
import SQLEditor, { SQLEditorRef } from '../SQLEditor';
import RoutineOperationModals from './RoutineOperationModals';
import InitialSaveNameModal from './InitialSaveNameModal';
import { EditorSetValueType, EditorType, SQLOptType } from '../../type';
import { staticMessage } from '@chat2db/ui';
import { IConsoleReturnExecuteSql, IBoundInfo, TreeNodeData } from '@/typings';
Expand Down Expand Up @@ -41,6 +42,7 @@ import {
getContentDiffEligibility,
getContentDiffOpenBlockReason,
} from '../../helper/contentDiffGuard';
import { normalizeSavedConsoleName, resolveInitialSavedConsoleName } from '../../helper/savedConsoleName';

interface ISQLEditorWithOperationProps {
id: string;
Expand Down Expand Up @@ -123,6 +125,9 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
const [contextTableIdentifier, setContextTableIdentifier] = useState<EditorTableIdentifier | null>(null);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [hasEditorContent, setHasEditorContent] = useState<boolean>(!!defaultSQL?.trim());
const [initialSaveNameModalOpen, setInitialSaveNameModalOpen] = useState(false);
const [initialSaveName, setInitialSaveName] = useState('');
const [initialSaveLoading, setInitialSaveLoading] = useState(false);
const handleEditorContentChange = useCallback((value: string) => {
setHasEditorContent(!!value.trim());
}, []);
Expand Down Expand Up @@ -815,8 +820,56 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
if (type !== WorkspaceTabType.CONSOLE || typeof dbInfo.consoleId !== 'number' || isTemporaryId(dbInfo.consoleId)) {
return;
}
saveConsole(getValue());
}, [dbInfo.consoleId, saveConsole, type]);
if (!hasSavedSqlRecord) {
if (!initialSaveNameModalOpen) {
setInitialSaveName(
resolveInitialSavedConsoleName({
workspaceTitle: workspaceTabsTitle,
databaseName: dbInfo.databaseName,
schemaName: dbInfo.schemaName,
fallback: i18n('workspace.savedConsole.untitled'),
}),
);
setInitialSaveNameModalOpen(true);
}
return;
}
void saveConsole(getValue(), { mode: 'manual' });
}, [
dbInfo.consoleId,
dbInfo.databaseName,
dbInfo.schemaName,
hasSavedSqlRecord,
initialSaveNameModalOpen,
getValue,
saveConsole,
type,
workspaceTabsTitle,
]);

const handleConfirmInitialSave = useCallback(async () => {
const name = normalizeSavedConsoleName(initialSaveName);
if (!name || initialSaveLoading) {
return;
}

setInitialSaveLoading(true);
try {
await saveConsole(getValue(), { mode: 'manual', initialName: name });
setInitialSaveNameModalOpen(false);
} catch {
// The request layer presents the error. Keep the name dialog open for retry.
} finally {
setInitialSaveLoading(false);
}
}, [getValue, initialSaveLoading, initialSaveName, saveConsole]);

const handleCancelInitialSave = useCallback(() => {
if (initialSaveLoading) {
return;
}
setInitialSaveNameModalOpen(false);
}, [initialSaveLoading]);

const handleSaveFile = () => {
const fileContent = sqlEditorRef.current?.getValue() ?? '';
Expand Down Expand Up @@ -976,6 +1029,14 @@ const SQLEditorWithOperation = forwardRef<ISQLEditorWithOperationRef, ISQLEditor
onConfirmMigration={handleConfirmRoutineMigration}
onCancelMigration={handleCancelRoutineMigration}
/>
<InitialSaveNameModal
open={initialSaveNameModalOpen}
name={initialSaveName}
loading={initialSaveLoading}
onNameChange={setInitialSaveName}
onConfirm={handleConfirmInitialSave}
onCancel={handleCancelInitialSave}
/>
</div>
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const normalizeSavedConsoleName = (value?: string) => value?.trim() || '';

export const resolveInitialSavedConsoleName = (params: {
workspaceTitle?: string;
databaseName?: string;
schemaName?: string;
fallback: string;
}) => {
const { workspaceTitle, databaseName, schemaName, fallback } = params;
return [workspaceTitle, databaseName, schemaName, fallback].map(normalizeSavedConsoleName).find(Boolean) || '';
};
Loading
Loading