Sql Query Manager .sql dosyasının Preview özelliği

This commit is contained in:
Sedat Öztürk 2026-05-29 11:26:10 +03:00
parent a3e66081e9
commit f5b32d5a6b
9 changed files with 107 additions and 13 deletions

View file

@ -46,6 +46,11 @@ public interface ISqlObjectManagerAppService : IApplicationService
/// </summary>
Task<List<SqlDataFileDto>> GetSqlDataFilesAsync(string dataDirectoryName = "SqlData", string relativePath = "");
/// <summary>
/// Reads a .sql seed file content from the selected data directory.
/// </summary>
Task<string> GetSqlDataFileContentAsync(string dataDirectoryName = "SqlData", string relativePath = "");
/// <summary>
/// Moves a SQL seed file between the selected data directory root and HostData.
/// </summary>

View file

@ -1005,6 +1005,25 @@ FROM (
}
}
[HttpGet("api/app/sql-object-manager/sql-data-file-content")]
public async Task<string> GetSqlDataFileContentAsync(
[FromQuery] string dataDirectoryName = "SqlData",
[FromQuery] string relativePath = "")
{
ValidateTenantAccess();
var rootPath = ResolveSqlDataOutputPath(dataDirectoryName);
var filePath = ResolveSqlDataChildPath(rootPath, relativePath);
if (!File.Exists(filePath))
throw new Volo.Abp.UserFriendlyException("SQL seed file was not found.");
if (!string.Equals(Path.GetExtension(filePath), ".sql", StringComparison.OrdinalIgnoreCase))
throw new Volo.Abp.UserFriendlyException("Only .sql files can be previewed.");
return await File.ReadAllTextAsync(filePath);
}
[HttpPost("api/app/sql-object-manager/move-sql-data-file")]
public Task MoveSqlDataFileAsync(MoveSqlDataFileDto input)
{

View file

@ -17774,6 +17774,12 @@
"en": "Select key column",
"tr": "Anahtar sütunu seç"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.ScriptLoadedToEditor",
"en": "Script loaded to editor",
"tr": "Komut dosyası düzenleyiciye yüklendi"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.IndexKeys",

View file

@ -92,6 +92,16 @@ export class SqlObjectManagerService {
{ apiName: this.apiName, ...config },
)
getSqlDataFileContent = (dataDirectoryName = 'SqlData', relativePath: string, config?: Partial<Config>) =>
apiService.fetchData<string, void>(
{
method: 'GET',
url: '/api/app/sql-object-manager/sql-data-file-content',
params: { dataDirectoryName, relativePath },
},
{ apiName: this.apiName, ...config },
)
moveSqlDataFile = (
input: { dataDirectoryName: string; sourceRelativePath: string; targetRelativePath: string },
config?: Partial<Config>,

View file

@ -16,6 +16,7 @@ import {
FaExclamationTriangle,
FaArrowLeft,
FaArrowRight,
FaEye,
} from 'react-icons/fa'
import { FaCheckCircle } from 'react-icons/fa'
import { useLocalization } from '@/utils/hooks/useLocalization'
@ -100,6 +101,7 @@ const SqlQueryManager = () => {
const [showSqlDataFilesDialog, setShowSqlDataFilesDialog] = useState(false)
const [isLoadingSqlDataFiles, setIsLoadingSqlDataFiles] = useState(false)
const [isMovingSqlDataFile, setIsMovingSqlDataFile] = useState(false)
const [isPreviewingSqlDataFile, setIsPreviewingSqlDataFile] = useState(false)
const [sqlDataRootFiles, setSqlDataRootFiles] = useState<SqlDataExplorerEntry[]>([])
const [sqlDataHostFiles, setSqlDataHostFiles] = useState<SqlDataExplorerEntry[]>([])
const [selectedRootSqlDataFiles, setSelectedRootSqlDataFiles] = useState<string[]>([])
@ -1118,6 +1120,47 @@ GO`,
}
}
const handlePreviewSqlDataFile = async (file: SqlDataExplorerEntry) => {
if (!file.relativePath || isPreviewingSqlDataFile) {
return
}
setIsPreviewingSqlDataFile(true)
try {
const response = await sqlObjectManagerService.getSqlDataFileContent(
sqlDataDirectoryName,
file.relativePath,
)
setState((prev) => ({
...prev,
editorContent: response.data || '',
executionResult: null,
tableColumns: null,
isDirty: false,
}))
setShowSqlDataFilesDialog(false)
toast.push(
<Notification type="success" title={translate('::App.Platform.Success')}>
{translate('::App.SqlQueryManager.ScriptLoadedToEditor') ||
'SQL dosyasi Query Editor icine yuklendi.'}
</Notification>,
{ placement: 'top-center' },
)
} catch (error: any) {
toast.push(
<Notification type="danger" title={translate('::App.Platform.Error')}>
{error.response?.data?.error?.message || 'SQL dosyasi okunamadi.'}
</Notification>,
{ placement: 'top-center' },
)
} finally {
setIsPreviewingSqlDataFile(false)
}
}
const renderSqlDataPane = (
title: string,
files: SqlDataExplorerEntry[],
@ -1154,28 +1197,39 @@ GO`,
return (
<li key={file.relativePath || file.fileName}>
<label
<div
className={`flex cursor-pointer items-center gap-3 px-3 py-2 text-xs ${
selected
? 'bg-blue-50 text-blue-700 dark:bg-blue-950/40 dark:text-blue-200'
: 'text-gray-700 hover:bg-gray-50 dark:text-gray-200 dark:hover:bg-gray-800'
}`}
>
<input
type="checkbox"
className="h-4 w-4 shrink-0"
checked={selected}
disabled={isMovingSqlDataFile}
onChange={() =>
toggleSqlDataFileSelection(setSelectedFiles, file.relativePath)
}
/>
<FaFileAlt className="shrink-0 text-gray-400" />
<span className="min-w-0 flex-1 truncate">{file.name || file.fileName}</span>
<label className="flex min-w-0 flex-1 cursor-pointer items-center gap-3">
<input
type="checkbox"
className="h-4 w-4 shrink-0"
checked={selected}
disabled={isMovingSqlDataFile || isPreviewingSqlDataFile}
onChange={() =>
toggleSqlDataFileSelection(setSelectedFiles, file.relativePath)
}
/>
<FaFileAlt className="shrink-0 text-gray-400" />
<span className="min-w-0 flex-1 truncate">{file.name || file.fileName}</span>
</label>
<span className="hidden shrink-0 text-xs text-gray-400 dark:text-gray-500 sm:inline">
{new Date(file.createdAt).toLocaleString()}
</span>
</label>
<Button
size="xs"
variant="plain"
icon={<FaEye />}
onClick={() => handlePreviewSqlDataFile(file)}
loading={isPreviewingSqlDataFile}
disabled={isMovingSqlDataFile || isPreviewingSqlDataFile}
title={translate('::App.Platform.Preview') || 'Preview'}
/>
</div>
</li>
)
})}