From 9689ef1bc688fad86f2f1b3cbf512f677e98c14b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?= <76204082+iamsedatozturk@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:13:58 +0300 Subject: [PATCH] =?UTF-8?q?Demo=20ve=20Raporun=20ilk=20seferde=20a=C3=A7?= =?UTF-8?q?=C4=B1lamamas=C4=B1n=C4=B1=20=C3=A7=C3=B6z=C3=BCmledim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomReportStorageWebExtension.cs | 65 +++++++++++++++++-- ui/src/components/layouts/PublicLayout.tsx | 13 ++-- ui/src/contexts/DemoContext.tsx | 19 ++++++ ui/src/views/public/Demo.tsx | 5 +- ui/src/views/public/Home.tsx | 9 ++- 5 files changed, 97 insertions(+), 14 deletions(-) create mode 100644 ui/src/contexts/DemoContext.tsx diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/ReportServices/CustomReportStorageWebExtension.cs b/api/src/Sozsoft.Platform.HttpApi.Host/ReportServices/CustomReportStorageWebExtension.cs index 6817621..6114099 100644 --- a/api/src/Sozsoft.Platform.HttpApi.Host/ReportServices/CustomReportStorageWebExtension.cs +++ b/api/src/Sozsoft.Platform.HttpApi.Host/ReportServices/CustomReportStorageWebExtension.cs @@ -3,9 +3,14 @@ using System.IO; using System.Linq; using System; using System.Reflection; +using System.Text.Json; using System.Threading.Tasks; +using DevExpress.DataAccess.Json; +using DevExpress.DataAccess.Sql; using DevExpress.XtraPrinting; using Microsoft.Extensions.DependencyInjection; +using Sozsoft.Platform.Entities; +using Volo.Abp.Domain.Repositories; using Volo.Abp.Users; namespace Sozsoft.Platform.ReportServices; @@ -186,10 +191,10 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens var storedReportName = GetStoredReportName(reportName, parameters); var isDynamicReport = IsDynamicReport(reportName); - var reportData = TryGetStoredReportData(storedReportName, parameters, isDynamicReport); + var reportData = await TryGetStoredReportDataAsync(storedReportName, parameters, isDynamicReport); if (reportData == null && !string.Equals(storedReportName, reportName, StringComparison.OrdinalIgnoreCase)) { - reportData = TryGetStoredReportData(reportName, parameters, isDynamicReport); + reportData = await TryGetStoredReportDataAsync(reportName, parameters, isDynamicReport); } if (reportData != null) { @@ -204,7 +209,7 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens throw new FaultException(new FaultReason(string.Format("Could not find report '{0}'.", url)), new FaultCode("Server"), "GetData"); } - private byte[] TryGetStoredReportData( + private async Task TryGetStoredReportDataAsync( string reportName, Dictionary parameters, bool isDynamicReport) @@ -215,14 +220,66 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens return null; } - ApplyReportParameters(report, parameters); if (isDynamicReport) { + await EmbedDynamicReportDataAsync(report, parameters); ApplyDynamicReportFooter(report); } + else + { + ApplyReportParameters(report, parameters); + } + return SaveReportLayout(report); } + private async Task EmbedDynamicReportDataAsync( + XtraReport report, + IReadOnlyDictionary parameters) + { + if (!parameters.TryGetValue("id", out var idValue) || !Guid.TryParse(idValue, out var reportTemplateId)) + { + throw new InvalidOperationException("A valid report template id is required."); + } + + using var scope = _serviceProvider.CreateScope(); + var repository = scope.ServiceProvider.GetRequiredService>(); + var template = await repository.FindAsync(reportTemplateId); + if (template == null) + { + throw new InvalidOperationException($"Report template '{reportTemplateId}' was not found."); + } + + // A stored DynamicReport layout can contain a named SqlDataSource. The cached document + // builder executes that source later on a background thread, where its connection can be + // stale or no longer carry the request's tenant context. Embed the tenant-scoped result in + // the layout so document generation no longer opens a second database connection. + foreach (var sqlDataSource in report.ComponentStorage.OfType().ToList()) + { + if (ReferenceEquals(report.DataSource, sqlDataSource)) + { + report.DataSource = null; + } + + report.ComponentStorage.Remove(sqlDataSource); + sqlDataSource.Dispose(); + } + + var dataSource = new JsonDataSource + { + Name = "DynamicReportData", + JsonSource = new CustomJsonSource(JsonSerializer.Serialize(new[] + { + new { template.HtmlContent } + })) + }; + dataSource.Fill(); + + report.ComponentStorage.Add(dataSource); + report.DataSource = dataSource; + report.DataMember = null; + } + private void ApplyDynamicReportFooter(XtraReport report) { var bottomMargin = report.Bands.OfType().FirstOrDefault(); diff --git a/ui/src/components/layouts/PublicLayout.tsx b/ui/src/components/layouts/PublicLayout.tsx index 99b2b53..8d29c96 100644 --- a/ui/src/components/layouts/PublicLayout.tsx +++ b/ui/src/components/layouts/PublicLayout.tsx @@ -22,6 +22,7 @@ import { useLocalization } from '@/utils/hooks/useLocalization' import LanguageSelector from '../template/LanguageSelector' import Demo from '@/views/public/Demo' import { ScrollContext } from '@/contexts/ScrollContext' +import { DemoProvider } from '@/contexts/DemoContext' import useDarkMode from '@/utils/hooks/useDarkmode' import { THEME_ENUM } from '@/constants/theme.constant' import { Button } from '../ui' @@ -170,8 +171,9 @@ const PublicLayout = () => { } return ( - -
+ setIsDemoOpen(true) }}> + +
{/* HEADER */}
{ {/* Demo Modal */} - setIsDemoOpen(false)} /> -
-
+ setIsDemoOpen(false)} /> +
+
+ ) } diff --git a/ui/src/contexts/DemoContext.tsx b/ui/src/contexts/DemoContext.tsx new file mode 100644 index 0000000..6735ce4 --- /dev/null +++ b/ui/src/contexts/DemoContext.tsx @@ -0,0 +1,19 @@ +import React, { createContext, useContext } from 'react' + +interface DemoContextValue { + openDemo: () => void +} + +const DemoContext = createContext(undefined) + +export const DemoProvider = DemoContext.Provider + +export const useDemo = () => { + const context = useContext(DemoContext) + + if (!context) { + throw new Error('useDemo must be used within a DemoProvider') + } + + return context +} diff --git a/ui/src/views/public/Demo.tsx b/ui/src/views/public/Demo.tsx index b358a81..7e684de 100644 --- a/ui/src/views/public/Demo.tsx +++ b/ui/src/views/public/Demo.tsx @@ -167,9 +167,10 @@ const Demo: React.FC = ({ isOpen, onClose }) => { onClick={onClose} title="Kapat" aria-label="Kapat" - variant="plain" + variant="default" shape="circle" - className="absolute top-4 right-4 !h-8 !w-8 !px-0 text-2xl text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100" + size="lg" + className="absolute top-4 right-4 !h-8 !w-8 !px-0 bg-gray-900 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100" > × diff --git a/ui/src/views/public/Home.tsx b/ui/src/views/public/Home.tsx index 3e9bb0a..54bbca2 100644 --- a/ui/src/views/public/Home.tsx +++ b/ui/src/views/public/Home.tsx @@ -18,6 +18,7 @@ import { DesignerSelection } from './designer/types' import { useDesignerState } from './designer/useDesignerState' import { getHome, HomeDto, saveHomePage } from '@/services/home.service' import { Button, Notification, toast } from '@/components/ui' +import { useDemo } from '@/contexts/DemoContext' interface HomeSlideServiceContent { icon: string @@ -272,6 +273,7 @@ function buildHomeContent(home: HomeDto | undefined, translate: (key: string) => } const Home: React.FC = () => { + const { openDemo } = useDemo() const { translate } = useLocalization() const { setLang } = useStoreActions((actions) => actions.locale) const { getConfig } = useStoreActions((actions) => actions.abpConfig) @@ -988,13 +990,14 @@ const Home: React.FC = () => {

- {content?.heroPrimaryCtaLabel}{' '} - +