AiBotAppService güncellemesi
This commit is contained in:
parent
ab955483eb
commit
9186792a98
12 changed files with 189 additions and 119 deletions
|
|
@ -8,5 +8,6 @@ public class AiBotDto : FullAuditedEntityDto<Guid>
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string ApiUrl { get; set; }
|
public string ApiUrl { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
public string Tenants { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,24 +42,31 @@ public static class LookupQueryValues
|
||||||
$"ORDER BY \"{DisplayExpr}\";";
|
$"ORDER BY \"{DisplayExpr}\";";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string TechnicalSkillsValues =
|
public static string TenantValues(bool alwaysName = false)
|
||||||
$"SELECT " +
|
{
|
||||||
$"\"Name\" AS \"Key\", " +
|
if (alwaysName)
|
||||||
$"\"Name\" AS \"Name\" " +
|
{
|
||||||
$"FROM \"{FullNameTable(TableNameEnum.Skill)}\" " +
|
return $"SELECT * FROM (" +
|
||||||
$"WHERE \"SkillTypeId\" IN (SELECT \"Id\" FROM \"{FullNameTable(TableNameEnum.SkillType)}\" WHERE \"Name\"='Technical Skills' ) " +
|
$"SELECT " +
|
||||||
$"ORDER BY \"Name\"";
|
$"\"AbpTenants\".\"Name\" AS \"Key\", " +
|
||||||
|
$"\"AbpTenants\".\"Name\" AS \"Name\" " +
|
||||||
public static string TenantValues =
|
$"FROM \"AbpTenants\"" +
|
||||||
$"SELECT * FROM (" +
|
$") AS \"List\" " +
|
||||||
$"SELECT NULL AS \"Key\", 'Host' AS \"Name\" " +
|
$"ORDER BY \"Name\"";
|
||||||
$"UNION ALL " +
|
}
|
||||||
$"SELECT " +
|
else
|
||||||
$"\"AbpTenants\".\"Id\" AS \"Key\", " +
|
{
|
||||||
$"\"AbpTenants\".\"Name\" AS \"Name\" " +
|
return $"SELECT * FROM (" +
|
||||||
$"FROM \"AbpTenants\"" +
|
$"SELECT NULL AS \"Key\", 'Host' AS \"Name\" " +
|
||||||
$") AS \"List\" " +
|
$"UNION ALL " +
|
||||||
$"ORDER BY \"Name\"";
|
$"SELECT " +
|
||||||
|
$"\"AbpTenants\".\"Id\" AS \"Key\", " +
|
||||||
|
$"\"AbpTenants\".\"Name\" AS \"Name\" " +
|
||||||
|
$"FROM \"AbpTenants\"" +
|
||||||
|
$") AS \"List\" " +
|
||||||
|
$"ORDER BY \"Name\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string LanguageKeyValues =
|
public static string LanguageKeyValues =
|
||||||
$"SELECT " +
|
$"SELECT " +
|
||||||
|
|
@ -231,4 +238,13 @@ public static class LookupQueryValues
|
||||||
$"FROM \"{TableNameResolver.GetFullTableName(nameof(TableNameEnum.SurveyQuestion))}\" " +
|
$"FROM \"{TableNameResolver.GetFullTableName(nameof(TableNameEnum.SurveyQuestion))}\" " +
|
||||||
$"WHERE \"IsDeleted\" = 'false' " +
|
$"WHERE \"IsDeleted\" = 'false' " +
|
||||||
$"ORDER BY \"QuestionText\";";
|
$"ORDER BY \"QuestionText\";";
|
||||||
|
|
||||||
|
public static string TechnicalSkillsValues =
|
||||||
|
$"SELECT " +
|
||||||
|
$"\"Name\" AS \"Key\", " +
|
||||||
|
$"\"Name\" AS \"Name\" " +
|
||||||
|
$"FROM \"{FullNameTable(TableNameEnum.Skill)}\" " +
|
||||||
|
$"WHERE \"SkillTypeId\" IN (SELECT \"Id\" FROM \"{FullNameTable(TableNameEnum.SkillType)}\" WHERE \"Name\"='Technical Skills' ) " +
|
||||||
|
$"ORDER BY \"Name\"";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ using Microsoft.AspNetCore.Authorization;
|
||||||
using Volo.Abp.Application.Dtos;
|
using Volo.Abp.Application.Dtos;
|
||||||
using Volo.Abp.Application.Services;
|
using Volo.Abp.Application.Services;
|
||||||
using Volo.Abp.Domain.Repositories;
|
using Volo.Abp.Domain.Repositories;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Sozsoft.Platform.AiBots;
|
namespace Sozsoft.Platform.AiBots;
|
||||||
|
|
||||||
|
|
@ -18,5 +20,29 @@ public class AiBotAppService : CrudAppService<
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task<PagedResultDto<AiBotDto>> GetListAsync(PagedAndSortedResultRequestDto input)
|
||||||
|
{
|
||||||
|
await CheckGetListPolicyAsync();
|
||||||
|
|
||||||
|
var query = await CreateFilteredQueryAsync(input);
|
||||||
|
|
||||||
|
if (CurrentTenant.IsAvailable && !string.IsNullOrWhiteSpace(CurrentTenant.Name))
|
||||||
|
{
|
||||||
|
var tenantName = CurrentTenant.Name;
|
||||||
|
query = query.Where(aiBot =>
|
||||||
|
string.IsNullOrWhiteSpace(aiBot.Tenants) ||
|
||||||
|
aiBot.Tenants.Contains($"\"{tenantName}\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalCount = await AsyncExecuter.CountAsync(query);
|
||||||
|
query = ApplySorting(query, input);
|
||||||
|
query = ApplyPaging(query, input);
|
||||||
|
|
||||||
|
var entities = await AsyncExecuter.ToListAsync(query);
|
||||||
|
var dtos = await MapToGetListOutputDtosAsync(entities);
|
||||||
|
|
||||||
|
return new PagedResultDto<AiBotDto>(totalCount, dtos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15116,6 +15116,12 @@
|
||||||
"en": "Is Tenant",
|
"en": "Is Tenant",
|
||||||
"tr": "Tenant"
|
"tr": "Tenant"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Listform.ListformField.Tenants",
|
||||||
|
"en": "Tenants",
|
||||||
|
"tr": "Tenantlar"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.Listform.ListformField.IsTransfer",
|
"key": "App.Listform.ListformField.IsTransfer",
|
||||||
|
|
|
||||||
|
|
@ -679,7 +679,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
DataSourceType = UiLookupDataSourceTypeEnum.Query,
|
DataSourceType = UiLookupDataSourceTypeEnum.Query,
|
||||||
DisplayExpr = "Name",
|
DisplayExpr = "Name",
|
||||||
ValueExpr = "Key",
|
ValueExpr = "Key",
|
||||||
LookupQuery = LookupQueryValues.TenantValues,
|
LookupQuery = LookupQueryValues.TenantValues(),
|
||||||
}),
|
}),
|
||||||
ColumnCustomizationJson = DefaultColumnCustomizationJson,
|
ColumnCustomizationJson = DefaultColumnCustomizationJson,
|
||||||
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
|
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
|
||||||
|
|
@ -1239,14 +1239,15 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
InsertFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
|
InsertFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
|
||||||
new() { FieldName = "Id", FieldDbType = DbType.Guid, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
|
new() { FieldName = "Id", FieldDbType = DbType.Guid, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
|
||||||
}),
|
}),
|
||||||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 750, true, true, true, true, false),
|
EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 650, true, true, true, true, false),
|
||||||
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>()
|
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>()
|
||||||
{
|
{
|
||||||
new() { Order=1, ColCount=2, ColSpan=1, ItemType="group", Items = [
|
new() { Order=1, ColCount=2, ColSpan=1, ItemType="group", Items = [
|
||||||
new EditingFormItemDto { Order=1, DataField="Name", ColSpan=1, EditorType2=EditorTypes.dxTextBox },
|
new EditingFormItemDto { Order=1, DataField="Name", ColSpan=1, EditorType2=EditorTypes.dxTextBox },
|
||||||
new EditingFormItemDto { Order=2, DataField="IsActive", ColSpan=1, EditorType2=EditorTypes.dxCheckBox },
|
new EditingFormItemDto { Order=2, DataField="IsActive", ColSpan=1, EditorType2=EditorTypes.dxCheckBox },
|
||||||
new EditingFormItemDto { Order=3, DataField="ApiUrl", ColSpan=2, EditorType2=EditorTypes.dxTextBox },
|
new EditingFormItemDto { Order=3, DataField="ApiUrl", ColSpan=2, EditorType2=EditorTypes.dxTextBox },
|
||||||
new EditingFormItemDto { Order=4, DataField="Description", ColSpan=2, EditorType2=EditorTypes.dxHtmlEditor, EditorOptions=EditorOptionValues.HtmlEditorOptions },
|
new EditingFormItemDto { Order=4, DataField="Tenants", ColSpan=2, EditorType2=EditorTypes.dxTagBox },
|
||||||
|
new EditingFormItemDto { Order=5, DataField="Description", ColSpan=2, EditorType2=EditorTypes.dxHtmlEditor, EditorOptions=EditorOptionValues.HtmlEditorOptions },
|
||||||
]}
|
]}
|
||||||
}),
|
}),
|
||||||
FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[]
|
FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[]
|
||||||
|
|
@ -1337,6 +1338,28 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
|
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
|
||||||
PivotSettingsJson = DefaultPivotSettingsJson
|
PivotSettingsJson = DefaultPivotSettingsJson
|
||||||
},
|
},
|
||||||
|
new ListFormField
|
||||||
|
{
|
||||||
|
ListFormCode = listForm.ListFormCode,
|
||||||
|
CultureName = LanguageCodes.En,
|
||||||
|
SourceDbType = DbType.String,
|
||||||
|
FieldName = "Tenants",
|
||||||
|
CaptionName = "App.Listform.ListformField.Tenants",
|
||||||
|
Width = 0,
|
||||||
|
ListOrderNo = 6,
|
||||||
|
Visible = true,
|
||||||
|
IsActive = true,
|
||||||
|
AllowSearch = true,
|
||||||
|
LookupJson = JsonSerializer.Serialize(new LookupDto {
|
||||||
|
DataSourceType = UiLookupDataSourceTypeEnum.Query,
|
||||||
|
DisplayExpr = "Name",
|
||||||
|
ValueExpr = "Key",
|
||||||
|
LookupQuery = LookupQueryValues.TenantValues(true),
|
||||||
|
}),
|
||||||
|
ColumnCustomizationJson = DefaultColumnCustomizationJson,
|
||||||
|
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
|
||||||
|
PivotSettingsJson = DefaultPivotSettingsJson
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ namespace Sozsoft.Platform.Entities;
|
||||||
public class AiBot : Entity<Guid>
|
public class AiBot : Entity<Guid>
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Description { get; set; }
|
|
||||||
public string ApiUrl { get; set; }
|
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
public string ApiUrl { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string Tenants { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,7 @@ public class PlatformDbContext :
|
||||||
b.Property(a => a.Name).IsRequired().HasMaxLength(128);
|
b.Property(a => a.Name).IsRequired().HasMaxLength(128);
|
||||||
b.Property(a => a.ApiUrl).HasMaxLength(256);
|
b.Property(a => a.ApiUrl).HasMaxLength(256);
|
||||||
b.Property(a => a.Description).HasColumnType("text");
|
b.Property(a => a.Description).HasColumnType("text");
|
||||||
|
b.Property(a => a.Tenants).HasColumnType("text");
|
||||||
|
|
||||||
b.HasIndex(x => new { x.Name }).IsUnique().HasFilter(null);
|
b.HasIndex(x => new { x.Name }).IsUnique().HasFilter(null);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
|
||||||
namespace Sozsoft.Platform.Migrations
|
namespace Sozsoft.Platform.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(PlatformDbContext))]
|
[DbContext(typeof(PlatformDbContext))]
|
||||||
[Migration("20260623105928_Initial")]
|
[Migration("20260623164647_Initial")]
|
||||||
partial class Initial
|
partial class Initial
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -699,6 +699,9 @@ namespace Sozsoft.Platform.Migrations
|
||||||
.HasMaxLength(128)
|
.HasMaxLength(128)
|
||||||
.HasColumnType("nvarchar(128)");
|
.HasColumnType("nvarchar(128)");
|
||||||
|
|
||||||
|
b.Property<string>("Tenants")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("Name")
|
b.HasIndex("Name")
|
||||||
|
|
@ -921,9 +921,10 @@ namespace Sozsoft.Platform.Migrations
|
||||||
{
|
{
|
||||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
|
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
|
||||||
Description = table.Column<string>(type: "text", nullable: true),
|
IsActive = table.Column<bool>(type: "bit", nullable: false),
|
||||||
ApiUrl = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
ApiUrl = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||||
IsActive = table.Column<bool>(type: "bit", nullable: false)
|
Description = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Tenants = table.Column<string>(type: "text", nullable: true)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
|
|
@ -696,6 +696,9 @@ namespace Sozsoft.Platform.Migrations
|
||||||
.HasMaxLength(128)
|
.HasMaxLength(128)
|
||||||
.HasColumnType("nvarchar(128)");
|
.HasColumnType("nvarchar(128)");
|
||||||
|
|
||||||
|
b.Property<string>("Tenants")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("Name")
|
b.HasIndex("Name")
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,19 @@ export interface AiBotDto extends FullAuditedEntityDto<string> {
|
||||||
name: string
|
name: string
|
||||||
apiUrl?: string
|
apiUrl?: string
|
||||||
description?: string
|
description?: string
|
||||||
|
tenants?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Types
|
||||||
export type ChatType = 'chat' | 'query' | 'analyze'
|
export type ChatType = 'chat' | 'query' | 'analyze'
|
||||||
|
|
||||||
export interface BaseContent {
|
export interface BaseContent {
|
||||||
type: ChatType
|
type: ChatType
|
||||||
question: string
|
question: string
|
||||||
sql: string | null
|
sql?: string | null
|
||||||
answer: string | any[]
|
answer?: string | any[] | null
|
||||||
chart?: string
|
chart?: string
|
||||||
error?: string
|
error?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MessageContent = string | BaseContent
|
export type MessageContent = string | BaseContent
|
||||||
|
|
@ -22,6 +24,13 @@ export type MessageContent = string | BaseContent
|
||||||
export interface Message {
|
export interface Message {
|
||||||
role: 'user' | 'assistant'
|
role: 'user' | 'assistant'
|
||||||
content: MessageContent
|
content: MessageContent
|
||||||
/** ISO string */
|
|
||||||
createdAt?: string
|
createdAt?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Conversation {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
messages: Message[]
|
||||||
|
createdAt: string
|
||||||
|
updatedAt: string
|
||||||
|
}
|
||||||
|
|
@ -4,41 +4,13 @@ import { useStoreState } from '@/store'
|
||||||
import { Avatar, Button, Drawer, Dropdown, ScrollBar } from '@/components/ui'
|
import { Avatar, Button, Drawer, Dropdown, ScrollBar } from '@/components/ui'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { aiService } from '@/services/ai.service'
|
import { aiService } from '@/services/ai.service'
|
||||||
import { AiBotDto } from '@/proxy/ai/models'
|
import { AiBotDto, BaseContent, Conversation, Message, MessageContent } from '@/proxy/ai/models'
|
||||||
import { Container } from '@/components/shared'
|
import { Container } from '@/components/shared'
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
import { APP_NAME } from '@/constants/app.constant'
|
import { APP_NAME } from '@/constants/app.constant'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { AI_ASSISTANT } from '@/constants/permission.constant'
|
import { AI_ASSISTANT } from '@/constants/permission.constant'
|
||||||
|
|
||||||
// Types
|
|
||||||
type ChatType = 'chat' | 'query' | 'analyze'
|
|
||||||
|
|
||||||
interface BaseContent {
|
|
||||||
type: ChatType
|
|
||||||
question: string
|
|
||||||
sql: string | null
|
|
||||||
answer: string | any[]
|
|
||||||
chart?: string
|
|
||||||
error?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type MessageContent = string | BaseContent
|
|
||||||
|
|
||||||
interface Message {
|
|
||||||
role: 'user' | 'assistant'
|
|
||||||
content: MessageContent
|
|
||||||
createdAt?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Conversation {
|
|
||||||
id: string
|
|
||||||
title: string
|
|
||||||
messages: Message[]
|
|
||||||
createdAt: string
|
|
||||||
updatedAt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const CONVERSATIONS_STORAGE_KEY = 'AiConversations'
|
const CONVERSATIONS_STORAGE_KEY = 'AiConversations'
|
||||||
const ACTIVE_CONVERSATION_STORAGE_KEY = 'AiActiveConversationId'
|
const ACTIVE_CONVERSATION_STORAGE_KEY = 'AiActiveConversationId'
|
||||||
|
|
||||||
|
|
@ -330,7 +302,6 @@ const Assistant = () => {
|
||||||
question: userMessage,
|
question: userMessage,
|
||||||
sessionId: conversationId,
|
sessionId: conversationId,
|
||||||
tenantName: tenant.tenantName ?? null,
|
tenantName: tenant.tenantName ?? null,
|
||||||
// description: selectedBotItem?.description?.replace(/\r?\n/g, '\\n'),
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -338,8 +309,12 @@ const Assistant = () => {
|
||||||
const raw = Array.isArray(data) ? data[0] : data
|
const raw = Array.isArray(data) ? data[0] : data
|
||||||
|
|
||||||
const mapped: BaseContent = {
|
const mapped: BaseContent = {
|
||||||
...raw,
|
type: raw?.type || 'chat',
|
||||||
result: raw.result || raw.answer || raw.error || 'Sonuç bulunamadı.',
|
question: raw?.question || userMessage,
|
||||||
|
sql: raw?.sql ?? null,
|
||||||
|
answer: raw?.answer ?? null,
|
||||||
|
chart: raw?.chart,
|
||||||
|
error: raw?.error ?? null,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2️⃣ Cevabı store'a ekle
|
// 2️⃣ Cevabı store'a ekle
|
||||||
|
|
@ -407,68 +382,73 @@ const Assistant = () => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{error ? (
|
{error && (
|
||||||
<div className="text-red-700 dark:text-red-200 bg-red-100 dark:bg-red-900/50 border border-red-300 dark:border-red-800 rounded p-2">
|
<div className="text-red-700 dark:text-red-200 bg-red-100 dark:bg-red-900/50 border border-red-300 dark:border-red-800 rounded p-2">
|
||||||
⚠️ <strong>Hata:</strong> {error}
|
⚠️ <strong>Hata:</strong> {error}
|
||||||
</div>
|
</div>
|
||||||
) : typeof answer === 'string' ? (
|
)}
|
||||||
renderFormattedText(answer)
|
|
||||||
) : Array.isArray(answer) ? (
|
{!error &&
|
||||||
answer.length === 0 ? (
|
(typeof answer === 'string' ? (
|
||||||
|
renderFormattedText(answer)
|
||||||
|
) : Array.isArray(answer) ? (
|
||||||
|
answer.length === 0 ? (
|
||||||
|
<div className="text-gray-500 italic">Sonuç bulunamadı.</div>
|
||||||
|
) : (
|
||||||
|
<div className="overflow-x-auto max-h-[400px] overflow-y-auto border border-gray-200 dark:border-gray-700 rounded">
|
||||||
|
<table className="table-auto w-full text-sm">
|
||||||
|
<thead className="bg-gray-100 dark:bg-gray-800 sticky top-0">
|
||||||
|
<tr>
|
||||||
|
{Object.keys(answer[0]).map((col) => (
|
||||||
|
<th
|
||||||
|
key={col}
|
||||||
|
className="border border-gray-200 dark:border-gray-700 px-2 py-1 text-left"
|
||||||
|
>
|
||||||
|
{col}
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{answer.map((row, rowIndex) => (
|
||||||
|
<tr key={rowIndex} className="hover:bg-gray-50 dark:hover:bg-gray-800">
|
||||||
|
{Object.keys(row).map((col, colIndex) => {
|
||||||
|
const val = row[col]
|
||||||
|
const display =
|
||||||
|
val === null || val === undefined
|
||||||
|
? '—'
|
||||||
|
: typeof val === 'boolean'
|
||||||
|
? val
|
||||||
|
? 'Evet'
|
||||||
|
: 'Hayır'
|
||||||
|
: typeof val === 'string' && val.endsWith('T00:00:00.000Z')
|
||||||
|
? new Date(val).toLocaleDateString('tr-TR')
|
||||||
|
: String(val)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<td
|
||||||
|
key={colIndex}
|
||||||
|
className="border border-gray-200 dark:border-gray-700 px-2 py-1"
|
||||||
|
>
|
||||||
|
{display}
|
||||||
|
</td>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
) : typeof answer === 'object' && answer !== null && (answer as any).message ? (
|
||||||
|
renderFormattedText(String((answer as any).message))
|
||||||
|
) : answer === null || answer === undefined ? (
|
||||||
<div className="text-gray-500 italic">Sonuç bulunamadı.</div>
|
<div className="text-gray-500 italic">Sonuç bulunamadı.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="overflow-x-auto max-h-[400px] overflow-y-auto border border-gray-200 dark:border-gray-700 rounded">
|
<pre className="text-xs bg-gray-100 dark:bg-gray-800 p-2 rounded border border-gray-200 dark:border-gray-700">
|
||||||
<table className="table-auto w-full text-sm">
|
{JSON.stringify(answer, null, 2)}
|
||||||
<thead className="bg-gray-100 dark:bg-gray-800 sticky top-0">
|
</pre>
|
||||||
<tr>
|
))}
|
||||||
{Object.keys(answer[0]).map((col) => (
|
|
||||||
<th
|
|
||||||
key={col}
|
|
||||||
className="border border-gray-200 dark:border-gray-700 px-2 py-1 text-left"
|
|
||||||
>
|
|
||||||
{col}
|
|
||||||
</th>
|
|
||||||
))}
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{answer.map((row, rowIndex) => (
|
|
||||||
<tr key={rowIndex} className="hover:bg-gray-50 dark:hover:bg-gray-800">
|
|
||||||
{Object.keys(row).map((col, colIndex) => {
|
|
||||||
const val = row[col]
|
|
||||||
const display =
|
|
||||||
val === null || val === undefined
|
|
||||||
? '—'
|
|
||||||
: typeof val === 'boolean'
|
|
||||||
? val
|
|
||||||
? 'Evet'
|
|
||||||
: 'Hayır'
|
|
||||||
: typeof val === 'string' && val.endsWith('T00:00:00.000Z')
|
|
||||||
? new Date(val).toLocaleDateString('tr-TR')
|
|
||||||
: String(val)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<td
|
|
||||||
key={colIndex}
|
|
||||||
className="border border-gray-200 dark:border-gray-700 px-2 py-1"
|
|
||||||
>
|
|
||||||
{display}
|
|
||||||
</td>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
) : typeof answer === 'object' && answer !== null && (answer as any).message ? (
|
|
||||||
renderFormattedText(String((answer as any).message))
|
|
||||||
) : (
|
|
||||||
<pre className="text-xs bg-gray-100 dark:bg-gray-800 p-2 rounded border border-gray-200 dark:border-gray-700">
|
|
||||||
{JSON.stringify(answer, null, 2)}
|
|
||||||
</pre>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{chart && (
|
{chart && (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue