├── .github └── workflows │ └── vale.yml ├── .gitignore ├── CODEOWNERS ├── CS ├── Directory.Packages.props ├── OutlookInspired.Blazor.Server │ ├── App.razor │ ├── BlazorApplication.cs │ ├── BlazorModule.cs │ ├── Charts │ │ ├── OpportunityPieChart.razor │ │ ├── SalesCustomerChart.razor │ │ └── SalesProductChart.razor │ ├── Components │ │ ├── BOImage.razor │ │ └── DxGrid │ │ │ ├── DxGridDetailRow.razor │ │ │ ├── DxGridDetailRow.razor.cs │ │ │ ├── MyDxGrid.razor │ │ │ └── MyDxGrid.razor.cs │ ├── Controllers │ │ ├── DisableInlineRowActionController.cs │ │ ├── DxGridListEditorController.cs │ │ └── PopupWindowSizeController.cs │ ├── Editors │ │ ├── DxHtmlPropertyEditor.cs │ │ ├── EnumPropertyEditor.cs │ │ ├── HyperLink │ │ │ ├── HyperLinkPropertyEditor.cs │ │ │ ├── Hyperlink.razor │ │ │ └── Hyperlink.razor.cs │ │ ├── Label │ │ │ ├── Label.razor │ │ │ ├── Label.razor.cs │ │ │ └── LabelPropertyEditor.cs │ │ ├── LayoutView │ │ │ ├── LayoutView.razor │ │ │ ├── LayoutView.razor.cs │ │ │ ├── LayoutView.razor.css │ │ │ ├── LayoutViewListEditor.cs │ │ │ ├── SideBySideLayout.razor │ │ │ └── SideBySideLayout.razor.css │ │ ├── LayoutViewStacked │ │ │ ├── StackedLayoutView.razor │ │ │ ├── StackedLayoutView.razor.cs │ │ │ ├── StackedLayoutView.razor.css │ │ │ └── StackedLayoutViewEditor.cs │ │ ├── Maps │ │ │ ├── DevExtremeMap.razor │ │ │ ├── DevExtremeMap.razor.cs │ │ │ ├── DevExtremeMap.razor.js │ │ │ ├── DxMapComponent.razor │ │ │ ├── DxMapComponent.razor.cs │ │ │ ├── DxMapHomeOfficePropertyEditor.cs │ │ │ └── MapItemListEditor.cs │ │ ├── PdfViewer │ │ │ ├── PdfViewerModel.cs │ │ │ └── PdfViewerPropertyEditor.cs │ │ └── Pivot │ │ │ ├── DxPivotGridComponent.razor │ │ │ ├── DxPivotGridComponent.razor.cs │ │ │ └── PivotGridListEditor.cs │ ├── Features │ │ ├── Customers │ │ │ ├── CustomerLayoutViewController.cs │ │ │ ├── CustomerListViewDetailRowController.cs │ │ │ └── CustomerStoresLayoutViewController.cs │ │ ├── Employees │ │ │ ├── EmployeeLayoutViewController.cs │ │ │ ├── Evaluations │ │ │ │ ├── EmployeeEvaluationColumnTemplate.razor │ │ │ │ ├── EmployeeEvaluationColumnTemplate.razor.css │ │ │ │ └── EmployeeEvaluationsController.cs │ │ │ ├── Maps │ │ │ │ └── MapsTravelModeViewController.cs │ │ │ └── Tasks │ │ │ │ ├── EmployeeTasksColumnTemplate.razor │ │ │ │ ├── EmployeeTasksColumnTemplate.razor.css │ │ │ │ └── EmployeeTasksController.cs │ │ ├── Evaluations │ │ │ └── SchedulerGroupTypeController.cs │ │ ├── Maps │ │ │ ├── MapItemListEditorController.cs │ │ │ └── SalesMapItemDxChartListEditorController.cs │ │ ├── Orders │ │ │ └── OrderListViewDetailRowController.cs │ │ ├── Products │ │ │ └── ProductLayoutViewController.cs │ │ ├── Quotes │ │ │ ├── BlazorQuoteAnalysisPivotGridListEditorController.cs │ │ │ └── BlazorQuoteMapItemListViewController.cs │ │ ├── ViewFilter │ │ │ └── ViewFilterDeleteController.cs │ │ └── WelcomeController.cs │ ├── Images │ │ └── ReadMe.txt │ ├── Model.xafml │ ├── OutlookInspired.Blazor.Server.csproj │ ├── Pages │ │ └── _Host.cshtml │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── ReadMe.txt │ ├── Services │ │ ├── CircuitHandlerProxy.cs │ │ └── ProxyHubConnectionHandler.cs │ ├── Startup.cs │ ├── _Imports.razor │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ │ ├── css │ │ └── site.css │ │ ├── favicon.ico │ │ └── images │ │ ├── Logo.svg │ │ └── SplashScreen.svg ├── OutlookInspired.MiddleTier │ ├── JWT │ │ ├── JwtTokenProviderService.cs │ │ └── WebApiAuthenticationController.cs │ ├── OutlookInspired.MiddleTier.csproj │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── ReadMe.txt │ ├── Startup.cs │ ├── appsettings.Development.json │ └── appsettings.json ├── OutlookInspired.Module │ ├── Attributes │ │ ├── Appearance │ │ │ ├── DeactivateActionAttribute.cs │ │ │ ├── ForbidCRUDAttribute.cs │ │ │ ├── ForbidDeleteAttribute.cs │ │ │ └── ForbidNavigation.cs │ │ ├── FontSizeDeltaAttribute.cs │ │ └── Validation │ │ │ ├── EmailAddressAttribute.cs │ │ │ ├── PhoneAttribute.cs │ │ │ ├── UrlAttribute.cs │ │ │ └── ZipCodeAttribute.cs │ ├── BusinessObjects │ │ ├── ApplicationUser.cs │ │ ├── ApplicationUserLoginInfo.cs │ │ ├── Crest.cs │ │ ├── Customer.cs │ │ ├── CustomerCommunication.cs │ │ ├── CustomerEmployee.cs │ │ ├── CustomerStore.cs │ │ ├── Employee.cs │ │ ├── EmployeeTask.cs │ │ ├── Evaluation.cs │ │ ├── MapItem.cs │ │ ├── Opportunity.cs │ │ ├── Order.cs │ │ ├── OrderItem.cs │ │ ├── OutlookInspiredBaseObject.cs │ │ ├── OutlookInspiredDbContext.cs │ │ ├── Period.cs │ │ ├── Picture.cs │ │ ├── Probation.cs │ │ ├── Product.cs │ │ ├── ProductCatalog.cs │ │ ├── ProductImage.cs │ │ ├── Quote.cs │ │ ├── QuoteAnalysis.cs │ │ ├── QuoteItem.cs │ │ ├── QuoteMapItem.cs │ │ ├── RoutePoint.cs │ │ ├── State.cs │ │ ├── TaskAttachedFile.cs │ │ ├── TaxRate.cs │ │ ├── ViewFilter.cs │ │ └── Welcome.cs │ ├── DatabaseUpdate │ │ ├── ReadMe.txt │ │ └── Updater.cs │ ├── EditorAliases.cs │ ├── Features │ │ ├── CloneView │ │ │ ├── CloneViewAttribute.cs │ │ │ └── CloneViewUpdater.cs │ │ ├── Customers │ │ │ ├── CustomerReportController.cs │ │ │ └── MapCustomerController.cs │ │ ├── Employees │ │ │ ├── CommunicationController.cs │ │ │ ├── MailMergeController.cs │ │ │ └── MapEmployeeController.cs │ │ ├── Maps │ │ │ ├── MapApiKeyProvider.cs │ │ │ ├── MapsSalesPeriodViewController.cs │ │ │ └── Markers.cs │ │ ├── Orders │ │ │ ├── FollowUpController.cs │ │ │ ├── InvoiceController.cs │ │ │ ├── MapOrderController.cs │ │ │ ├── OrdersReportController.cs │ │ │ ├── PayController.cs │ │ │ ├── RefundController.cs │ │ │ └── ShipmentDetailController.cs │ │ ├── Products │ │ │ ├── MapProductController.cs │ │ │ └── ProductReportController.cs │ │ ├── Quotes │ │ │ ├── MapOpportunitiesController.cs │ │ │ ├── OpportunitiesFilterListViewController.cs │ │ │ ├── OpportunitiesListViewController.cs │ │ │ ├── QuoteAnalysisListViewController.cs │ │ │ └── QuoteMapItemListViewController.cs │ │ ├── Reports │ │ │ ├── ProtectReportActionItemsViewController.cs │ │ │ └── ShowReportController.cs │ │ └── ViewFilterController.cs │ ├── Images │ │ ├── AllTasks.png │ │ ├── Automation.png │ │ ├── Commission.png │ │ ├── Doctor.svg │ │ ├── EvaluationNo.svg │ │ ├── EvaluationYes.svg │ │ ├── High.svg │ │ ├── HighPriority.png │ │ ├── Low.svg │ │ ├── LowPriority.png │ │ ├── Medium.svg │ │ ├── MediumPriority.png │ │ ├── Miss.svg │ │ ├── Monitors.png │ │ ├── Mr.svg │ │ ├── Mrs.svg │ │ ├── Ms.svg │ │ ├── NormalPriority.png │ │ ├── OnLeave.png │ │ ├── PriorityHigh.svg │ │ ├── PriorityLow.svg │ │ ├── PriorityNormal.svg │ │ ├── PriorityUrgent.svg │ │ ├── Probation.png │ │ ├── Projectors.png │ │ ├── Salaried.png │ │ ├── Skype.svg │ │ ├── Summary.svg │ │ ├── TVs.png │ │ ├── Terminated.png │ │ ├── Unlike.svg │ │ ├── Urgent.png │ │ ├── VideoPlayers.png │ │ ├── icon-email-16.png │ │ ├── icon-home-phone-16.png │ │ └── icon-mobile-phone-16.png │ ├── Model.DesignedDiffs.xafml │ ├── ModelInterfaces.cs │ ├── ModelUpdaters │ │ ├── DashboardViewsModelUpdater.cs │ │ ├── DataAccessModeUpdater.cs │ │ └── NavigationItemsModelUpdater.cs │ ├── Module.cs │ ├── OutlookInspired.Module.csproj │ ├── ReadMe.txt │ ├── Resources │ │ ├── MailMerge │ │ │ ├── FollowUp.docx │ │ │ ├── Month Award.docx │ │ │ ├── Order.docx │ │ │ ├── OrderItem.docx │ │ │ ├── Probation Notice.docx │ │ │ ├── Service Excellence.docx │ │ │ ├── Thank You Note.docx │ │ │ └── Welcome to DevAV.docx │ │ ├── Reports │ │ │ ├── CustomerContactsDirectory.cs │ │ │ ├── CustomerContactsDirectory.resx │ │ │ ├── CustomerLocationsDirectory.cs │ │ │ ├── CustomerLocationsDirectory.resx │ │ │ ├── CustomerProfile.cs │ │ │ ├── CustomerProfile.resx │ │ │ ├── CustomerSalesSummaryReport.cs │ │ │ ├── CustomerSalesSummaryReport.resx │ │ │ ├── FedExGroundLabel.cs │ │ │ ├── FedExGroundLabel.resx │ │ │ ├── ProductOrders.cs │ │ │ ├── ProductOrders.resx │ │ │ ├── ProductProfile.cs │ │ │ ├── ProductProfile.resx │ │ │ ├── ProductSalesSummary.cs │ │ │ ├── ProductSalesSummary.resx │ │ │ ├── ProductTopSalesperson.cs │ │ │ ├── ProductTopSalesperson.resx │ │ │ ├── SalesRevenueAnalysisReport.cs │ │ │ ├── SalesRevenueAnalysisReport.resx │ │ │ ├── SalesRevenueReport.cs │ │ │ └── SalesRevenueReport.resx │ │ └── Welcome.pdf │ └── Welcome.html ├── OutlookInspired.Win │ ├── App.config │ ├── Controllers │ │ └── DisableSkinsController.cs │ ├── Editors │ │ ├── ColumnViewUserControl.Designer.cs │ │ ├── ColumnViewUserControl.cs │ │ ├── ColumnViewUserControl.resx │ │ ├── DxHtmlEditor │ │ │ ├── BlazorWebViewShortcutsController.cs │ │ │ └── DxHtmlPropertyEditor.cs │ │ ├── EnumPropertyEditor.cs │ │ ├── GridListEditor │ │ │ ├── ColumnViewListEditor.cs │ │ │ ├── FontSizeController.cs │ │ │ └── NewItemRowHandlingModeController.cs │ │ ├── HyperLinkPropertyEditor.cs │ │ ├── LabelControlPropertyEditor.cs │ │ ├── Maps │ │ │ ├── MapControlHomeOfficePropertyEditor.cs │ │ │ └── MapItemListEditor.cs │ │ ├── PdfViewerEditor.cs │ │ ├── PrintLayoutRichTextEditor.cs │ │ └── ProgressEditor │ │ │ └── PropertyEditorController.cs │ ├── ExpressApp.ico │ ├── Features │ │ ├── Customers │ │ │ ├── CustomerColumnViewListEditorController.cs │ │ │ ├── CustomerGridView.Designer.cs │ │ │ ├── CustomerGridView.cs │ │ │ ├── CustomerGridView.resx │ │ │ ├── CustomerLayoutView.Designer.cs │ │ │ ├── CustomerLayoutView.cs │ │ │ ├── CustomerLayoutView.resx │ │ │ ├── CustomerStoreColumnViewListEditorController.cs │ │ │ ├── CustomerStoreView.Designer.cs │ │ │ ├── CustomerStoreView.cs │ │ │ └── CustomerStoreView.resx │ │ ├── Employees │ │ │ ├── EmployeeColumnViewListEditorController.cs │ │ │ ├── EmployeesLayoutView.Designer.cs │ │ │ ├── EmployeesLayoutView.cs │ │ │ ├── EmployeesLayoutView.resx │ │ │ └── MapsTravelModeViewController.cs │ │ ├── Evaluations │ │ │ └── SchedulerListEditorController.cs │ │ ├── Maps │ │ │ ├── Colorizer.cs │ │ │ ├── MapItemChartListEditorController.cs │ │ │ └── MapItemListEditorController.cs │ │ ├── Orders │ │ │ ├── OrderColumnViewListEditorController.cs │ │ │ ├── OrderDetailView.Designer.cs │ │ │ ├── OrderDetailView.cs │ │ │ ├── OrderDetailView.resx │ │ │ ├── OrderGridView.Designer.cs │ │ │ ├── OrderGridView.cs │ │ │ └── OrderGridView.resx │ │ ├── Products │ │ │ ├── ProductCardView.Designer.cs │ │ │ ├── ProductCardView.cs │ │ │ ├── ProductCardView.resx │ │ │ └── ProductColumnViewListEditorController.cs │ │ └── Quotes │ │ │ ├── QuoteAnalysisPivotGridListEditorController.cs │ │ │ ├── WinOpportunitiesChartListViewController.cs │ │ │ └── WinQuoteMapItemListEditorController.cs │ ├── Images │ │ ├── ExpressAppLogo.png │ │ ├── Logo.svg │ │ ├── ReadMe.txt │ │ └── SplashScreenImage.svg │ ├── Initialization.cs │ ├── Model.xafml │ ├── OutlookInspired.Win.csproj │ ├── Program.cs │ ├── Properties │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── ReadMe.txt │ ├── Startup.cs │ ├── WinApplication.cs │ ├── WinModule.cs │ ├── XafDemoSplashScreen.Designer.cs │ ├── XafDemoSplashScreen.cs │ ├── _Imports.razor │ └── wwwroot │ │ ├── css │ │ └── app.css │ │ └── index.html └── OutlookInspired.sln ├── Data └── OutlookInspired.zip ├── Images ├── AzureBuild.png ├── BOImage.png ├── BlazorChart.png ├── BlazorFontDelta.png ├── BlazorTravelDistance.jpg ├── CardViews.png ├── CustomerReportAction.png ├── DomainModel.png ├── EmployeeCard.png ├── EmployeeWinLayout.png ├── EnumPropertyEditorWin.png ├── FollowUp.png ├── HostUI.png ├── HyperLinkEditorWin.png ├── HyperLinkLabel.png ├── LabelWinEditor.png ├── ManageTenants.png ├── Opportunities.png ├── OpportunitiesListView.png ├── OpportunitiesMap.png ├── OrderDetailView.png ├── OrderInvoice.png ├── PdfViewerBlazor.png ├── PdfViewerWin.png ├── ProductCardView.png ├── ProductReports.png ├── ProgressEditorWin.png ├── RevenueAnalysis.png ├── Scheduler.png ├── ShowInDocumentIcon.png ├── Solution.png ├── StoresView.png ├── TasksView.png ├── TenantUI.png ├── TestsFolders.png ├── ViewFilterAction.png ├── ViewFilterView.png ├── WatermarkReport.png ├── WinFontDelta.png ├── WinMasterDetailGrid.png ├── WinOppurtunityMaps.png ├── WinProductLayout.png ├── WinSalesMap.png ├── WinTravelDistance.png └── XafImg.png ├── LICENSE ├── LICENSE.txt ├── Readme.md ├── azure-pipelines.yml ├── config.json └── job-template.yml /.github/workflows/vale.yml: -------------------------------------------------------------------------------- 1 | name: vale-validation 2 | on: 3 | pull_request: 4 | paths: 5 | - README.md 6 | - readme.md 7 | - Readme.md 8 | 9 | jobs: 10 | vale: 11 | name: runner / vale 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: clone repo 15 | uses: actions/checkout@v4 16 | - name: clone vale-styles repo 17 | uses: actions/checkout@v4 18 | with: 19 | repository: DevExpress/vale-styles 20 | path: vale-styles 21 | ssh-key: ${{ secrets.VALE_STYLES_ACCESS_KEY }} 22 | - name: copy vale rules to the root repo 23 | run: shopt -s dotglob && cp -r ./vale-styles/vale/* . 24 | - name: vale linter check 25 | uses: DevExpress/vale-action@reviewdog 26 | with: 27 | files: '["README.md", "readme.md", "Readme.md"]' 28 | fail_on_error: true 29 | filter_mode: nofilter 30 | reporter: github-check 31 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @DevExpressExampleBot -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/App.razor: -------------------------------------------------------------------------------- 1 | @DxResourceManager.RegisterScripts(c => 2 | { 3 | CommonResources.JQueryJS.Position = CommonResources.DevExtremeJS.Position - 50; 4 | c.Register(CommonResources.JQueryJS); 5 | c.Register(CommonResources.DevExtremeJS); 6 | c.Register(new DxResource("https://cdn3.devexpress.com/jslib/23.2.3/js/vectormap-data/usa.js", CommonResources.DevExtremeJS.Position + 50)); 7 | }) 8 | 9 | 10 | 11 | 12 | 13 | 14 | Not found 15 |

Sorry, there's nothing at this address.

16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/BlazorApplication.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Blazor; 3 | using DevExpress.ExpressApp.SystemModule; 4 | using DevExpress.ExpressApp.Utils; 5 | 6 | namespace OutlookInspired.Blazor.Server; 7 | 8 | public class OutlookInspiredBlazorApplication : BlazorApplication { 9 | public OutlookInspiredBlazorApplication(){ 10 | AboutInfo.Instance.Version = "Version " + AssemblyInfo.FileVersion; 11 | AboutInfo.Instance.Copyright = AssemblyInfo.AssemblyCopyright + " All Rights Reserved"; 12 | } 13 | protected override SettingsStorage CreateLogonParameterStoreCore() => new EmptySettingsStorage(); 14 | 15 | protected override void OnSetupStarted() { 16 | base.OnSetupStarted(); 17 | #if DEBUG || EASYTEST 18 | if(System.Diagnostics.Debugger.IsAttached && CheckCompatibilityType == CheckCompatibilityType.DatabaseSchema) { 19 | DatabaseUpdateMode = DatabaseUpdateMode.UpdateDatabaseAlways; 20 | } 21 | #endif 22 | } 23 | 24 | class EmptySettingsStorage : SettingsStorage { 25 | public override string LoadOption(string optionPath, string optionName) => null; 26 | public override void SaveOption(string optionPath, string optionName, string optionValue) { } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/BlazorModule.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.Persistent.BaseImpl.EF; 3 | using System.ComponentModel; 4 | 5 | 6 | namespace OutlookInspired.Blazor.Server; 7 | [ToolboxItemFilter("Xaf.Platform.Blazor")] 8 | public sealed class OutlookInspiredBlazorModule : ModuleBase { 9 | private void Application_CreateCustomUserModelDifferenceStore(object sender, CreateCustomModelDifferenceStoreEventArgs e) { 10 | e.Store = new ModelDifferenceDbStore((XafApplication)sender, typeof(ModelDifference), false, "Blazor"); 11 | e.Handled = true; 12 | } 13 | 14 | public override void Setup(XafApplication application) { 15 | base.Setup(application); 16 | application.CreateCustomUserModelDifferenceStore += Application_CreateCustomUserModelDifferenceStore; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Charts/OpportunityPieChart.razor: -------------------------------------------------------------------------------- 1 | @using System.Linq.Expressions 2 | @using DevExpress.ExpressApp.Blazor.Editors 3 | @using DevExpress.ExpressApp.Blazor.Editors.Models 4 | @using DevExpress.ExpressApp.Utils 5 | @using OutlookInspired.Module.BusinessObjects 6 | @using System.Drawing 7 | 8 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
@context.Point.Argument
18 |
Sales: @($"${context.Point.Value:#,0.}")
19 |
20 |
21 | 22 | 23 | @code { 24 | [CascadingParameter] public DxChartListEditor ChartEditor { get; set; } 25 | 26 | protected override void OnParametersSet() 27 | { 28 | base.OnParametersSet(); 29 | if (ChartEditor.ChartModel is DxPieChartModel pieChart) 30 | { 31 | pieChart.SetAttribute("style", "margin-top:100px"); 32 | pieChart.Diameter = 1; 33 | pieChart.InnerDiameter = 0.5; 34 | pieChart.StartAngle = 0; 35 | pieChart.SegmentDirection = PieChartSegmentDirection.Clockwise; 36 | pieChart.CustomizeSeriesPoint = e 37 | => e.PointAppearance.Color = ColorTranslator.FromHtml(e.Point.DataItems.Cast().First().Stage.Color()); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Charts/SalesCustomerChart.razor: -------------------------------------------------------------------------------- 1 | @using OutlookInspired.Module.BusinessObjects 2 | 3 | 8 | 9 | 10 |
11 | @context.Point.SeriesName: @($"{(decimal)context.Point.Value:$0,.#K}") 12 |
13 |
14 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Charts/SalesProductChart.razor: -------------------------------------------------------------------------------- 1 | @using OutlookInspired.Module.BusinessObjects 2 | 3 | 8 | 9 | 10 |
11 | @context.Point.SeriesName: @($"{(decimal)context.Point.Value:$0,.#K}") 12 |
13 |
14 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Components/BOImage.razor: -------------------------------------------------------------------------------- 1 | @using DevExpress.ExpressApp.Blazor.Services 2 | @using DevExpress.ExpressApp.Utils 3 | @inject IImageUrlService ImageUrlService 4 | 5 |
0 ? $"height: {Size}px; width: {Size}px; mask-size: {Size}px; -webkit-mask-size: {Size}px;" : "") @Styles">
6 | 7 | 8 | @code { 9 | [Parameter] 10 | public Type ObjectType { get; set; } 11 | 12 | private string _imageUrl; 13 | 14 | protected override void OnInitialized(){ 15 | base.OnInitialized(); 16 | var modelClass = CaptionHelper.ApplicationModel.BOModel.GetClass(ObjectType); 17 | var imageName = modelClass.ImageName; 18 | _imageUrl = $"/{ImageUrlService.GetImageUrl(imageName)}"; 19 | AltText = modelClass.Caption; 20 | 21 | } 22 | [Parameter(CaptureUnmatchedValues = true)] 23 | public Dictionary Attributes { get; set; } 24 | 25 | [Parameter] 26 | public string AltText { get; set; } 27 | [Parameter] 28 | public string Styles { get; set; } 29 | [Parameter] 30 | public string Color { get; set; } 31 | 32 | [Parameter] 33 | public int Size{ get; set; } = 16; 34 | [Parameter] 35 | public string CssClass { get; set; } 36 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Components/DxGrid/DxGridDetailRow.razor: -------------------------------------------------------------------------------- 1 | @using OutlookInspired.Blazor.Server.Components 2 | 3 | @foreach (var tab in Tabs){ 4 | @tab.caption 5 | } 6 | 7 | @RenderFragment 8 | 9 | @code { 10 | [Parameter] 11 | public EventCallback ActiveTabIndexChanged{ get; set; } 12 | [Parameter] 13 | public RenderFragment RenderFragment{ get; set; } 14 | [Parameter] 15 | public IEnumerable<(string caption,Type objectType)> Tabs { get; set; } 16 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Components/DxGrid/DxGridDetailRow.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | 3 | namespace OutlookInspired.Blazor.Server.Components.DxGrid{ 4 | public class DxGridDetailRowModel:DevExpress.ExpressApp.Blazor.Components.Models.ComponentModelBase{ 5 | public override Type ComponentType => typeof(DxGridDetailRow); 6 | public IEnumerable<(string caption,Type objectType)> Tabs { 7 | get=>GetPropertyValue>()??[]; 8 | set => SetPropertyValue(value); 9 | } 10 | 11 | public EventCallback ActiveTabIndexChanged{ 12 | get => GetPropertyValue>(); 13 | set => SetPropertyValue(value); 14 | } 15 | public RenderFragment RenderFragment{ 16 | get => GetPropertyValue(); 17 | set => SetPropertyValue(value); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Components/DxGrid/MyDxGrid.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | @foreach (var column in Columns){ 4 | 5 | } 6 | 7 | 8 | @foreach (var item in SummaryItems){ 9 | 10 | } 11 | 12 | 13 | 14 | @code { 15 | private object[] _data; 16 | 17 | [Parameter] 18 | public IEnumerable Columns { get; set; } 19 | [Parameter] 20 | public IEnumerable SummaryItems { get; set; } 21 | [Parameter] 22 | public IEnumerable Data { get; set; } 23 | 24 | [Parameter] 25 | public bool AllowSelectRowByClick { get; set; } 26 | 27 | protected override void OnInitialized(){ 28 | base.OnInitialized(); 29 | _data = Data.ToArray(); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Controllers/DisableInlineRowActionController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Blazor.SystemModule; 3 | 4 | namespace OutlookInspired.Blazor.Server.Controllers { 5 | public class DisableInlineRowActionController : ViewController { 6 | protected override void OnActivated() { 7 | base.OnActivated(); 8 | Frame.GetController()?.Active.SetItemValue("BlazorTemporary", false); 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Controllers/DxGridListEditorController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Blazor.Editors; 3 | 4 | namespace OutlookInspired.Blazor.Server.Controllers { 5 | public class DxGridListEditorController : ViewController { 6 | protected override void OnViewControlsCreated() { 7 | base.OnViewControlsCreated(); 8 | if (View.Editor is not DxGridListEditor editor) return; 9 | editor.RowClickMode = RowClickMode.SelectOnSingleProcessOnDouble; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Controllers/PopupWindowSizeController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Blazor.Templates; 3 | 4 | namespace OutlookInspired.Blazor.Server.Controllers{ 5 | public class PopupWindowSizeController:WindowController{ 6 | public PopupWindowSizeController() => TargetWindowType=WindowType.Main; 7 | protected override void OnActivated(){ 8 | base.OnActivated(); 9 | Application.CustomizeTemplate+=ApplicationOnCustomizeTemplate; 10 | } 11 | 12 | protected override void OnDeactivated(){ 13 | base.OnDeactivated(); 14 | Application.CustomizeTemplate-=ApplicationOnCustomizeTemplate; 15 | } 16 | 17 | private void ApplicationOnCustomizeTemplate(object sender, CustomizeTemplateEventArgs e){ 18 | if (e.Template is not IPopupWindowTemplateSize size) return; 19 | size.MaxWidth = "90vw"; 20 | size.Width = "90vw"; 21 | size.MaxHeight = "90vh"; 22 | size.Height = "90vh"; 23 | 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/EnumPropertyEditor.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Blazor.Components; 2 | using DevExpress.ExpressApp.Blazor.Editors; 3 | using DevExpress.ExpressApp.Editors; 4 | using DevExpress.ExpressApp.Model; 5 | using DevExpress.ExpressApp.Utils; 6 | using Microsoft.AspNetCore.Components; 7 | using EditorAliases = OutlookInspired.Module.EditorAliases; 8 | 9 | namespace OutlookInspired.Blazor.Server.Editors { 10 | [PropertyEditor(typeof(Enum), EditorAliases.EnumImageOnlyEditor, false)] 11 | public class EnumPropertyEditor(Type objectType, IModelMemberViewItem model) 12 | : DevExpress.ExpressApp.Blazor.Editors.EnumPropertyEditor(objectType, model){ 13 | protected override RenderFragment CreateViewComponentCore(object dataContext){ 14 | var value = this.GetPropertyValue(dataContext); 15 | if (value == null) return base.CreateViewComponentCore(dataContext); 16 | var enumValueImageName = value is string stringValue 17 | ? ImageLoader.Instance.GetEnumValueImageName(Enum.Parse(MemberInfo.MemberType, stringValue)) 18 | : ImageLoader.Instance.GetEnumValueImageName(value); 19 | return ComboBoxIconItem.Create(null, enumValueImageName); 20 | 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/HyperLink/HyperLinkPropertyEditor.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Blazor.Components.Models; 2 | using DevExpress.ExpressApp.Blazor.Editors; 3 | using DevExpress.ExpressApp.Editors; 4 | using DevExpress.ExpressApp.Model; 5 | using Microsoft.AspNetCore.Components; 6 | using EditorAliases = OutlookInspired.Module.EditorAliases; 7 | 8 | namespace OutlookInspired.Blazor.Server.Editors.HyperLink { 9 | [PropertyEditor(typeof(string), EditorAliases.HyperLinkPropertyEditor, false)] 10 | public class HyperLinkPropertyEditor(Type objectType, IModelMemberViewItem model) 11 | : StringPropertyEditor(objectType, model){ 12 | protected override RenderFragment CreateViewComponentCore(object dataContext) { 13 | var displayValue = this.GetPropertyDisplayValue(dataContext); 14 | var hyperLinkModel = new HyperlinkModel { 15 | Text = displayValue, 16 | Href = $"mailto:{displayValue}" 17 | }; 18 | return hyperLinkModel.GetComponentContent(); 19 | } 20 | 21 | 22 | } 23 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/HyperLink/Hyperlink.razor: -------------------------------------------------------------------------------- 1 | @Text 2 | @code { 3 | [Parameter] public string Text { get; set; } 4 | [Parameter] public string Style { get; set; } 5 | [Parameter] public string Href { get; set; } 6 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/HyperLink/Hyperlink.razor.cs: -------------------------------------------------------------------------------- 1 | namespace OutlookInspired.Blazor.Server.Editors.HyperLink { 2 | 3 | public class HyperlinkModel : DevExpress.ExpressApp.Blazor.Components.Models.ComponentModelBase{ 4 | public string Text { 5 | get => GetPropertyValue(); 6 | set => SetPropertyValue(value); 7 | } 8 | public string Style { 9 | get => GetPropertyValue(); 10 | set => SetPropertyValue(value); 11 | } 12 | public string Href { 13 | get => GetPropertyValue(); 14 | set => SetPropertyValue(value); 15 | } 16 | public override Type ComponentType => typeof(Hyperlink); 17 | } 18 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/Label/Label.razor: -------------------------------------------------------------------------------- 1 | 
@Text
2 | 3 | @code { 4 | [Parameter] public string Text { get; set; } 5 | [Parameter] public string Style { get; set; } 6 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/Label/Label.razor.cs: -------------------------------------------------------------------------------- 1 | namespace OutlookInspired.Blazor.Server.Editors.Label{ 2 | 3 | public class LabelModel : DevExpress.ExpressApp.Blazor.Components.Models.ComponentModelBase{ 4 | public string Text{ 5 | get => GetPropertyValue(); 6 | set => SetPropertyValue(value); 7 | } 8 | 9 | public string Style{ 10 | get => GetPropertyValue(); 11 | set => SetPropertyValue(value); 12 | } 13 | 14 | public override Type ComponentType => typeof(Label); 15 | } 16 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/Label/LabelPropertyEditor.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Blazor.Editors; 2 | using DevExpress.ExpressApp.Editors; 3 | using DevExpress.ExpressApp.Model; 4 | using DevExpress.XtraRichEdit; 5 | using OutlookInspired.Module.Attributes; 6 | using EditorAliases = OutlookInspired.Module.EditorAliases; 7 | 8 | namespace OutlookInspired.Blazor.Server.Editors.Label{ 9 | [PropertyEditor(typeof(object), EditorAliases.LabelPropertyEditor, false)] 10 | public class LabelPropertyEditor(Type objectType, IModelMemberViewItem model) 11 | : BlazorPropertyEditorBase(objectType, model){ 12 | private static readonly RichEditDocumentServer RichEditDocumentServer = new(); 13 | public override LabelModel ComponentModel => (LabelModel)base.ComponentModel; 14 | protected override LabelModel CreateComponentModel() 15 | => new(){ Style = MemberInfo.FindAttribute()?.Style() }; 16 | 17 | protected override void ReadValueCore() { 18 | base.ReadValueCore(); 19 | switch (PropertyValue){ 20 | case null: 21 | return; 22 | case byte[] bytes:{ 23 | using var memoryStream = new MemoryStream((bytes)); 24 | RichEditDocumentServer.LoadDocument(memoryStream,DocumentFormat.OpenXml); 25 | ComponentModel.Text = RichEditDocumentServer.Text; 26 | break; 27 | } 28 | default: 29 | ComponentModel.Text = $"{PropertyValue}"; 30 | break; 31 | } 32 | } 33 | protected override object GetControlValueCore() => ComponentModel.Text; 34 | } 35 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/LayoutView/LayoutView.razor: -------------------------------------------------------------------------------- 1 | @implements IDisposable 2 | @using System.ComponentModel 3 |
4 | @if (_data!=null){ 5 | if (_data.Any()){ 6 | 7 | @foreach (var entity in _data){ 8 | 9 | } 10 | 11 | } 12 |

RECORDS: @_data.Length

13 | } 14 |
15 | 16 | 17 | @code { 18 | private object[] _data; 19 | 20 | [Parameter][EditorRequired] 21 | public IEnumerable Data { get; set; } 22 | [Parameter] 23 | public Func ImageSelector { get; set; } 24 | [Parameter] 25 | public Func HeaderSelector { get; set; } 26 | [Parameter] 27 | public Func FooterSelector { get; set; } 28 | [Parameter] 29 | public EventCallback SelectionChanged{ get; set; } 30 | [Parameter] 31 | public EventCallback ProcessSelectedObject{ get; set; } 32 | [Parameter] 33 | public Func> InfoItemsSelector { get; set; } 34 | public BindingList SelectedCards { get; } = new(){RaiseListChangedEvents = true}; 35 | 36 | protected override void OnInitialized(){ 37 | base.OnInitialized(); 38 | SelectedCards.ListChanged+=SelectedCardsOnListChanged; 39 | } 40 | 41 | protected override void OnParametersSet(){ 42 | base.OnParametersSet(); 43 | _data = Data as object[] ?? Data?.ToArray(); 44 | } 45 | 46 | private void SelectedCardsOnListChanged(object sender, ListChangedEventArgs e){ 47 | if (e.ListChangedType != ListChangedType.ItemAdded) return; 48 | var selectedCard = SelectedCards[e.NewIndex]; 49 | foreach (var card in SelectedCards.Where(card => card != selectedCard).ToArray()){ 50 | SelectedCards.Remove(card); 51 | } 52 | StateHasChanged(); 53 | } 54 | 55 | public void Dispose() => SelectedCards.ListChanged-=SelectedCardsOnListChanged; 56 | 57 | 58 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/LayoutView/LayoutView.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | 3 | namespace OutlookInspired.Blazor.Server.Editors.LayoutView{ 4 | 5 | public class LayoutViewModel:DevExpress.ExpressApp.Blazor.Components.Models.ComponentModelBase{ 6 | public Func ImageSelector{ 7 | get => GetPropertyValue>(); 8 | set => SetPropertyValue(value); 9 | } 10 | public EventCallback SelectionChanged{ 11 | get => GetPropertyValue>(); 12 | set => SetPropertyValue(value); 13 | } 14 | public EventCallback ProcessSelectedObject{ 15 | get => GetPropertyValue(); 16 | set => SetPropertyValue(value); 17 | } 18 | public Func HeaderSelector{ 19 | get => GetPropertyValue>(); 20 | set => SetPropertyValue(value); 21 | } 22 | public Func FooterSelector{ 23 | get => GetPropertyValue>(); 24 | set => SetPropertyValue(value); 25 | } 26 | public Func> InfoItemsSelector{ 27 | get => GetPropertyValue>>(); 28 | set => SetPropertyValue(value); 29 | } 30 | 31 | public IEnumerable Data{ 32 | get => GetPropertyValue>(); 33 | set => SetPropertyValue(value); 34 | } 35 | 36 | public override Type ComponentType => typeof(LayoutView); 37 | } 38 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/LayoutView/LayoutView.razor.css: -------------------------------------------------------------------------------- 1 | .store-card-container { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | overflow-x: hidden; 6 | overflow-y: auto; 7 | height: 100vh; 8 | align-items: flex-start; 9 | align-content: flex-start; 10 | } 11 | 12 | .store-card-container > div { 13 | margin-bottom: 8px; 14 | } 15 | 16 | .store-card-container::-webkit-scrollbar { 17 | width: 12px; 18 | } 19 | 20 | .store-card-container::-webkit-scrollbar-thumb { 21 | background-color: darkgrey; 22 | outline: 1px solid slategrey; 23 | } 24 | 25 | .store-card-container { 26 | scrollbar-width: thin; 27 | scrollbar-color: darkgrey slategrey; 28 | } 29 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/LayoutView/SideBySideLayout.razor.css: -------------------------------------------------------------------------------- 1 | .ellipsis3Lines { 2 | display: -webkit-box; 3 | -webkit-line-clamp: 3; 4 | -webkit-box-orient: vertical; 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | max-width: 100%; 8 | line-height: 1.2em; 9 | max-height: 4.4em; 10 | } 11 | 12 | .card { 13 | flex: 0 0 auto; 14 | margin-right: 16px; 15 | max-width: calc(50% - 16px); 16 | } 17 | .ellipsis { 18 | white-space: nowrap; 19 | overflow: hidden; 20 | text-overflow: ellipsis; 21 | max-width: 100%; 22 | } 23 | .col-md-8 p { 24 | word-wrap: break-word; 25 | overflow: hidden; 26 | text-overflow: ellipsis; 27 | max-width: 100%; 28 | } 29 | .card-footer { 30 | .card-footer { 31 | padding: 10px 10px 20px 10px; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/LayoutViewStacked/StackedLayoutView.razor: -------------------------------------------------------------------------------- 1 | 
2 | @if (_data != null){ 3 | if (_data.Any()){ 4 | @foreach (var entity in _data){ 5 |
6 |
7 | @BodySelector(entity) 8 |
9 | 12 |
13 | } 14 | } 15 |

RECORDS: @_data.Length

16 | } 17 |
18 | 19 | 20 | @code { 21 | private object[] _data; 22 | 23 | [Parameter][EditorRequired] 24 | public IEnumerable Data { get; set; } 25 | [Parameter] 26 | public Func ImageSelector { get; set; } 27 | [Parameter] 28 | public Func BodySelector { get; set; } 29 | 30 | 31 | protected override void OnParametersSet(){ 32 | base.OnParametersSet(); 33 | _data = Data as object[] ?? Data?.ToArray(); 34 | } 35 | 36 | string ToBase64Image(byte[] bytes) 37 | =>bytes==null?"": $"data:{FileType(bytes)};base64,{Convert.ToBase64String(bytes)}"; 38 | 39 | string FileType(byte[] value) 40 | => value switch{ 41 | { Length: > 0 } when IsMaskMatch(value, 0, 77, 77) || IsMaskMatch(value,0, 73, 73) => "tiff", 42 | { Length: > 0 } when IsMaskMatch(value,1, 80, 78, 71) => "png", 43 | { Length: > 0 } when IsMaskMatch(value,0, 71, 73, 70, 56) => "gif", 44 | { Length: > 0 } when IsMaskMatch(value, 0, 255, 216) => "jpeg", 45 | { Length: > 0 } when IsMaskMatch(value,0, 66, 77) => "bmp", 46 | _ => "" 47 | }; 48 | 49 | bool IsMaskMatch( byte[] byteArray, int offset, params byte[] mask) 50 | => byteArray != null && byteArray.Length >= offset + mask.Length && 51 | !mask.Where((t, i) => byteArray[offset + i] != t).Any(); 52 | 53 | 54 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/LayoutViewStacked/StackedLayoutView.razor.cs: -------------------------------------------------------------------------------- 1 | namespace OutlookInspired.Blazor.Server.Editors.LayoutViewStacked{ 2 | 3 | public class StackedLayoutViewModel:DevExpress.ExpressApp.Blazor.Components.Models.ComponentModelBase{ 4 | public Func ImageSelector{ 5 | get => GetPropertyValue>(); 6 | set => SetPropertyValue(value); 7 | } 8 | 9 | public Func BodySelector{ 10 | get => GetPropertyValue>(); 11 | set => SetPropertyValue(value); 12 | } 13 | public IEnumerable Data{ 14 | get => GetPropertyValue>(); 15 | set => SetPropertyValue(value); 16 | } 17 | 18 | public override Type ComponentType => typeof(StackedLayoutView); 19 | } 20 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/LayoutViewStacked/StackedLayoutView.razor.css: -------------------------------------------------------------------------------- 1 | .store-card-container { 2 | display: flex; 3 | flex-wrap: wrap; 4 | gap: 10px; 5 | } 6 | .stacked-card { 7 | flex: 1 1 150px; 8 | max-width: 150px; 9 | display: flex; 10 | flex-direction: column; 11 | align-items: center; 12 | text-align: center; 13 | } 14 | .stacked-body, .stacked-footer { 15 | padding: 5px; 16 | } 17 | .stacked-footer { 18 | display: flex; 19 | justify-content: center; 20 | align-items: center; 21 | } 22 | .img-fluid { 23 | max-width: 100%; 24 | height: auto; 25 | } 26 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/Maps/DevExtremeMap.razor.js: -------------------------------------------------------------------------------- 1 | const dataSourceMap = { 2 | 'usa': DevExpress.viz.map.sources.usa, 3 | }; 4 | 5 | 6 | export function addMapToElement(element,height, layers, bounds, attributes, annotationData, dotNetHelper) { 7 | layers[0].dataSource = dataSourceMap[layers[0].dataSource]; 8 | 9 | return $(element).dxVectorMap({ 10 | layers: layers, 11 | bounds: bounds, 12 | height: height, 13 | tooltip: { 14 | enabled: true, 15 | zIndex: 10000, 16 | customizeTooltip: function (arg) { 17 | return arg.layer.type === 'marker' ? { text: arg.attribute('tooltip') } : null; 18 | } 19 | }, 20 | onClick: arg => { 21 | const clickedElement = arg.target; 22 | if (clickedElement != null) { 23 | clickedElement.selected(!clickedElement.selected()); 24 | dotNetHelper.invokeMethodAsync('OnSelectionChanged', attributes.map(f => clickedElement.attribute(f)).filter(val => val != null)); 25 | } 26 | }, 27 | annotations: annotationData.map(s => { return { coordinates: s.coordinates, text: s.data} }), 28 | commonAnnotationSettings : { 29 | type: 'text', 30 | font:{ 31 | color:"#FFFFFF" 32 | } 33 | } 34 | }).dxVectorMap('instance'); 35 | 36 | } 37 | 38 | export function dispose(element) { 39 | if (!element) return; 40 | $(element).dxVectorMap('dispose'); 41 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/Maps/DxMapComponent.razor: -------------------------------------------------------------------------------- 1 | @using DevExpress.Persistent.Base 2 | @using OutlookInspired.Module.Features.Maps 3 | @inject IMapApiKeyProvider ApiKeyProvider 4 | 5 | 6 | 7 | 8 | @foreach (var entity in Markers){ 9 | 10 | 11 | 12 | 13 | } 14 | 15 | 16 | 17 | 18 | @foreach (var entity in Markers){ 19 | 20 | } 21 | 22 | 23 | 24 | 25 | 26 | 27 | @code { 28 | [Parameter][EditorRequired] 29 | public Dictionary Markers{ get; set; } 30 | [Parameter][EditorRequired] 31 | public IMapsMarker Center{ get; set; } 32 | [Parameter][EditorRequired] 33 | public MapRouteMode MapRouteMode{ get; set; } 34 | private string GetLocation(IMapsMarker mapsMarker) => $"{mapsMarker.Latitude}, {mapsMarker.Longitude}"; 35 | 36 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/Maps/DxMapComponent.razor.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Blazor; 2 | using DevExpress.ExpressApp.Blazor.Components.Models; 3 | using DevExpress.Persistent.Base; 4 | 5 | namespace OutlookInspired.Blazor.Server.Editors.Maps{ 6 | public class DxMapModel : ComponentModelBase { 7 | public override Type ComponentType => typeof(DxMapComponent); 8 | 9 | public Dictionary Markers{ 10 | get => GetPropertyValue>(); 11 | set => SetPropertyValue(value); 12 | } 13 | public IMapsMarker Center{ 14 | get => GetPropertyValue(); 15 | set => SetPropertyValue(value); 16 | } 17 | 18 | public MapRouteMode MapRouteMode{ 19 | get => GetPropertyValue(); 20 | set => SetPropertyValue(value); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/Maps/DxMapHomeOfficePropertyEditor.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Blazor.Components.Models; 2 | using DevExpress.ExpressApp.Blazor.Editors; 3 | using DevExpress.ExpressApp.Editors; 4 | using DevExpress.ExpressApp.Model; 5 | using DevExpress.Persistent.Base; 6 | using OutlookInspired.Module; 7 | using OutlookInspired.Module.BusinessObjects; 8 | using EditorAliases = OutlookInspired.Module.EditorAliases; 9 | 10 | namespace OutlookInspired.Blazor.Server.Editors.Maps{ 11 | [PropertyEditor(typeof(IMapsMarker),EditorAliases.MapHomeOfficePropertyEditor, false)] 12 | public class DxMapHomeOfficePropertyEditor(Type objectType, IModelMemberViewItem model) : BlazorPropertyEditorBase(objectType, model){ 13 | 14 | protected override IComponentModel CreateComponentModel() => new DxMapModel(); 15 | public override DxMapModel ComponentModel => (DxMapModel)base.ComponentModel; 16 | protected override void ReadValueCore(){ 17 | base.ReadValueCore(); 18 | var modelHomeOffice = ((IModelOptionsHomeOffice)Model.Application.Options).HomeOffice; 19 | ComponentModel.Markers = new Dictionary{ 20 | { "Location", (IMapsMarker)View.CurrentObject }, 21 | { "HomeOffice", new MapsMarker("Home Office",modelHomeOffice.Latitude, modelHomeOffice.Longitude) } 22 | }; 23 | ComponentModel.Center=ComponentModel.Markers["Location"]; 24 | } 25 | 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/PdfViewer/PdfViewerModel.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Blazor.PdfViewer; 2 | using DevExpress.Blazor.Reporting.Models; 3 | using DevExpress.ExpressApp.Blazor.Components.Models; 4 | using Microsoft.AspNetCore.Components; 5 | 6 | namespace OutlookInspired.Blazor.Server.Editors.PdfViewer { 7 | public class PdfViewerModel : ComponentModelBase { 8 | public byte[] DocumentContent { 9 | get => GetPropertyValue(); 10 | set => SetPropertyValue(value); 11 | } 12 | public string CssClass { 13 | get => GetPropertyValue(); 14 | set => SetPropertyValue(value); 15 | } 16 | public bool IsSinglePagePreview { 17 | get => GetPropertyValue(); 18 | set => SetPropertyValue(value); 19 | } 20 | public EventCallback CustomizeToolbar { 21 | get => GetPropertyValue>(); 22 | set => SetPropertyValue(value); 23 | } 24 | public override Type ComponentType => typeof(DxPdfViewer); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/PdfViewer/PdfViewerPropertyEditor.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Blazor.Reporting.Models; 2 | using DevExpress.ExpressApp.Blazor.Components.Models; 3 | using DevExpress.ExpressApp.Blazor.Editors; 4 | using DevExpress.ExpressApp.Editors; 5 | using DevExpress.ExpressApp.Model; 6 | using Microsoft.AspNetCore.Components; 7 | using EditorAliases = OutlookInspired.Module.EditorAliases; 8 | 9 | namespace OutlookInspired.Blazor.Server.Editors.PdfViewer { 10 | [PropertyEditor(typeof(byte[]), EditorAliases.PdfViewerEditor)] 11 | public class PdfViewerPropertyEditor(Type objectType, IModelMemberViewItem model) 12 | : BlazorPropertyEditorBase(objectType, model){ 13 | public override PdfViewerModel ComponentModel => (PdfViewerModel)base.ComponentModel; 14 | protected override IComponentModel CreateComponentModel() 15 | => new PdfViewerModel { 16 | CssClass = "pe-pdf-viewer", 17 | CustomizeToolbar = EventCallback.Factory.Create(this, m => m.AllItems.Clear()) 18 | }; 19 | protected override void ReadValueCore() { 20 | base.ReadValueCore(); 21 | ComponentModel.DocumentContent = (byte[])PropertyValue; 22 | } 23 | } 24 | 25 | 26 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/Pivot/DxPivotGridComponent.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | @foreach (var field in Fields){ 4 | 6 | 7 | @if (field.IsProgressBar){ 8 | 9 | } 10 | else if (!string.IsNullOrEmpty(field.DisplayFormat)){ 11 | @string.Format(field.DisplayFormat, context) 12 | } 13 | else{ 14 | @context 15 | } 16 | 17 | 18 | } 19 | 20 | 21 | 22 | 23 | @code { 24 | private MyPivotGrid _pivotGrid; 25 | 26 | [Parameter][EditorRequired] 27 | public IEnumerable Data { get; set; } 28 | [Parameter][EditorRequired] 29 | public IEnumerable Fields { get; set; } 30 | [Parameter] 31 | public bool ExpandAllRows{ get; set; } 32 | protected override void OnAfterRender(bool firstRender){ 33 | base.OnAfterRender(firstRender); 34 | if (!ExpandAllRows)return; 35 | foreach (var row in _pivotGrid.Model.State.Data.Rows){ 36 | row.IsExpanded = true; 37 | } 38 | _pivotGrid.Model.Update(); 39 | } 40 | 41 | 42 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Editors/Pivot/DxPivotGridComponent.razor.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Blazor; 2 | using DevExpress.Blazor.Internal; 3 | using DevExpress.Blazor.PivotGrid.Internal; 4 | 5 | namespace OutlookInspired.Blazor.Server.Editors.Pivot; 6 | 7 | public class DxPivotGridModel : DevExpress.ExpressApp.Blazor.Components.Models.ComponentModelBase{ 8 | public IEnumerable Data { 9 | get => GetPropertyValue>()??Enumerable.Empty(); 10 | set => SetPropertyValue(value); 11 | } 12 | public IEnumerable Fields { 13 | get => GetPropertyValue>(); 14 | set => SetPropertyValue(value); 15 | } 16 | 17 | public bool ExpandAllRows { 18 | get => GetPropertyValue(); 19 | set => SetPropertyValue(value); 20 | } 21 | public override Type ComponentType => typeof(DxPivotGridComponent); 22 | } 23 | 24 | public interface IPivotField{ 25 | string Name{ get; } 26 | PivotGridSortOrder SortOrder{ get; } 27 | PivotGridFieldArea Area{ get; } 28 | PivotGridGroupInterval GroupInterval{ get; } 29 | string Caption{ get; } 30 | PivotGridSummaryType SummaryType{ get; } 31 | string DisplayFormat{ get; } 32 | bool IsProgressBar{ get; } 33 | 34 | } 35 | 36 | public class MyPivotGrid : DxPivotGrid{ 37 | public new MyPivotGridModel Model => (MyPivotGridModel)base.Model; 38 | protected override DevExpress.Blazor.Base.PivotGridModelBase CreateModelCore() => new MyPivotGridModel(this); 39 | } 40 | 41 | public class MyPivotGridModel(DxPivotGrid pivotGridComponent) : PivotGridModel(pivotGridComponent){ 42 | public new void Update() => base.Update(); 43 | public new PivotGridState State => base.State; 44 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Customers/CustomerLayoutViewController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using OutlookInspired.Blazor.Server.Editors.LayoutView; 3 | using OutlookInspired.Module.BusinessObjects; 4 | 5 | namespace OutlookInspired.Blazor.Server.Features.Customers{ 6 | public class CustomerLayoutViewController:ObjectViewController{ 7 | public CustomerLayoutViewController() => TargetViewId = Customer.LayoutViewListView; 8 | 9 | protected override void OnViewControlsCreated(){ 10 | base.OnViewControlsCreated(); 11 | var model = ((LayoutViewListEditor)View.Editor).Control; 12 | model.ImageSelector = o => ((Customer)o).Logo; 13 | model.HeaderSelector = o => ((Customer)o).Name; 14 | model.InfoItemsSelector = o => { 15 | var customer = ((Customer)o); 16 | return new Dictionary{ 17 | { "HOME OFFICE", customer.HomeOfficeLine }, 18 | { "BILLING ADDRESS", customer.BillingAddressLine } 19 | }; 20 | }; 21 | } 22 | 23 | } 24 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Customers/CustomerStoresLayoutViewController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using OutlookInspired.Blazor.Server.Editors.LayoutViewStacked; 3 | using OutlookInspired.Module.BusinessObjects; 4 | 5 | namespace OutlookInspired.Blazor.Server.Features.Customers { 6 | public class CustomerStoresLayoutViewController : ObjectViewController { 7 | protected override void OnViewControlsCreated() { 8 | base.OnViewControlsCreated(); 9 | if(View.Editor is StackedLayoutViewEditor editor) { 10 | var model = editor.Control; 11 | model.ImageSelector = o => ((CustomerStore)o).Crest.LargeImage; 12 | model.BodySelector = o => ((CustomerStore)o).City; 13 | } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Employees/EmployeeLayoutViewController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using OutlookInspired.Blazor.Server.Editors.LayoutView; 3 | using OutlookInspired.Module.BusinessObjects; 4 | 5 | namespace OutlookInspired.Blazor.Server.Features.Employees { 6 | public class EmployeeLayoutViewController : ObjectViewController { 7 | protected override void OnViewControlsCreated() { 8 | base.OnViewControlsCreated(); 9 | if(View.Editor is LayoutViewListEditor editor) { 10 | var model = editor.Control; 11 | model.ImageSelector = o => ((Employee)o).Picture?.Data; 12 | model.HeaderSelector = o => ((Employee)o).FullName; 13 | model.InfoItemsSelector = o => { 14 | var employee = (Employee)o; 15 | return new Dictionary{ 16 | { "ADDRESS", employee.Address }, 17 | { "EMAIL", $"{employee.Email}" }, 18 | { "PHONE", employee.HomePhone } 19 | }; 20 | }; 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Employees/Evaluations/EmployeeEvaluationColumnTemplate.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 |
@Subject
@Manager
RAISE
@Description
BONUS
9 |
12 | 13 | @code { 14 | [Parameter] 15 | public string Subject { get; set; } 16 | 17 | [Parameter] 18 | public string RaiseImage { get; set; } 19 | [Parameter] 20 | public string BonusImage { get; set; } 21 | [Parameter] 22 | public string Description { get; set; } 23 | [Parameter] 24 | public string Style { get; set; } 25 | [Parameter] 26 | public string Manager { get; set; } 27 | 28 | public static RenderFragment Create(string subject,string raiseImage, string bonusImage,string description,string style, string manager) 29 | => @; 32 | } 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Employees/Evaluations/EmployeeEvaluationColumnTemplate.razor.css: -------------------------------------------------------------------------------- 1 | table { 2 | table-layout: auto; 3 | width: 100%; 4 | } 5 | .evaluations-td { 6 | white-space: nowrap; 7 | overflow: hidden; 8 | text-overflow: ellipsis; 9 | max-width: 100%; 10 | visibility: visible; 11 | } 12 | .evaluations-description { 13 | white-space: normal; 14 | } 15 | td { 16 | vertical-align: top; 17 | } 18 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Employees/Evaluations/EmployeeEvaluationsController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Blazor.Editors; 3 | using DevExpress.ExpressApp.Utils; 4 | using OutlookInspired.Module.Attributes; 5 | using OutlookInspired.Module.BusinessObjects; 6 | 7 | namespace OutlookInspired.Blazor.Server.Features.Employees.Evaluations{ 8 | 9 | public class EmployeeEvaluationsController:ObjectViewController{ 10 | public EmployeeEvaluationsController() => TargetViewId = Evaluation.EmployeeEvaluationsChildListView; 11 | 12 | protected override void OnViewControlsCreated(){ 13 | base.OnViewControlsCreated(); 14 | if (View.Editor is not DxGridListEditor editor) return; 15 | var subjectDataColumnModel = editor.GridDataColumnModels.First(model => model.FieldName==nameof(Evaluation.Subject)); 16 | subjectDataColumnModel.HeaderCaptionTemplate = _ => _ => { }; 17 | subjectDataColumnModel.CellDisplayTemplate = context => { 18 | var evaluation = ((Evaluation)context.DataItem); 19 | var memberInfo = ((IObjectSpaceLink)context.DataItem).ObjectSpace.TypesInfo.FindTypeInfo(typeof(Evaluation)).FindMember(context.DataColumn.FieldName); 20 | var fontSizeDeltaAttribute = memberInfo.FindAttribute(); 21 | return EmployeeEvaluationColumnTemplate.Create(evaluation.Subject, 22 | ImageLoader.Instance.GetEnumValueImageName(evaluation.Raise), 23 | ImageLoader.Instance.GetEnumValueImageName(evaluation.Bonus), 24 | evaluation.Description, fontSizeDeltaAttribute?.Style(), evaluation.Manager.FullName); 25 | }; 26 | 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Employees/Maps/MapsTravelModeViewController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Blazor; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Actions; 4 | using DevExpress.ExpressApp.Templates; 5 | using DevExpress.Persistent.Base; 6 | using OutlookInspired.Blazor.Server.Editors.Maps; 7 | using OutlookInspired.Module.BusinessObjects; 8 | 9 | namespace OutlookInspired.Blazor.Server.Features.Employees.Maps{ 10 | public class MapsTravelModeViewController:ObjectViewController{ 11 | private readonly SingleChoiceAction _action; 12 | 13 | public MapsTravelModeViewController(){ 14 | TargetViewId = Employee.MapsDetailView; 15 | _action = new SingleChoiceAction(this,"TravelMode",PredefinedCategory.PopupActions); 16 | _action.Caption = "Travel Mode"; 17 | _action.Items.AddRange([new ChoiceActionItem("Driving", MapRouteMode.Driving){ ImageName = "Driving" }, 18 | new ChoiceActionItem("Walking", MapRouteMode.Walking){ ImageName = "Walking" } 19 | ]); 20 | _action.SelectedItem = _action.Items.First(); 21 | _action.ItemType=SingleChoiceActionItemType.ItemIsOperation; 22 | _action.ImageMode=ImageMode.UseItemImage; 23 | _action.DefaultItemMode = DefaultItemMode.LastExecutedItem; 24 | _action.PaintStyle=ActionItemPaintStyle.Image; 25 | _action.Executed+=ActionOnExecuted; 26 | } 27 | 28 | private void ActionOnExecuted(object sender, ActionBaseEventArgs e) 29 | => View.GetItems().First().ComponentModel.MapRouteMode = (MapRouteMode)_action.SelectedItem.Data; 30 | 31 | 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Employees/Tasks/EmployeeTasksColumnTemplate.razor: -------------------------------------------------------------------------------- 1 | @inject IJSRuntime JsRuntime 2 |
3 |
4 |
5 | @Subject 6 |
7 |
8 | @Date 9 |
10 |
11 |
12 |
13 | @Description 14 |
15 |
16 |
17 |
18 | 19 |
20 |
21 |
22 | @code { 23 | [Parameter] 24 | public string Subject { get; set; } 25 | [Parameter] 26 | public string Description { get; set; } 27 | [Parameter] 28 | public int Progress { get; set; } 29 | [Parameter] 30 | public string Date { get; set; } 31 | 32 | public static RenderFragment Create(string subject,string description,int progress, string date) 33 | => @; 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Employees/Tasks/EmployeeTasksColumnTemplate.razor.css: -------------------------------------------------------------------------------- 1 | .tasks-div { 2 | white-space: nowrap; 3 | overflow: hidden; 4 | text-overflow: ellipsis; 5 | max-width: 100%; 6 | visibility: visible; 7 | } 8 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Employees/Tasks/EmployeeTasksController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Blazor.Editors; 3 | using OutlookInspired.Module.BusinessObjects; 4 | 5 | namespace OutlookInspired.Blazor.Server.Features.Employees.Tasks{ 6 | public class EmployeeTasksController:ObjectViewController{ 7 | public EmployeeTasksController() => TargetViewId=EmployeeTask.AssignedTasksChildListView; 8 | 9 | protected override void OnViewControlsCreated(){ 10 | base.OnViewControlsCreated(); 11 | if (View.Editor is not DxGridListEditor editor) return; 12 | var subjectDataColumnModel = editor.GridDataColumnModels.First(model => model.FieldName==nameof(EmployeeTask.Subject)); 13 | subjectDataColumnModel.HeaderCaptionTemplate = _ => _ => { }; 14 | 15 | subjectDataColumnModel.CellDisplayTemplate = value => { 16 | var employeeTask = (EmployeeTask)value.DataItem; 17 | return EmployeeTasksColumnTemplate.Create(employeeTask.Subject,employeeTask.DescriptionText,employeeTask.Completion, 18 | employeeTask.DueDate.GetValueOrDefault().ToString("MMMM dd, yyyy")); 19 | }; 20 | 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Evaluations/SchedulerGroupTypeController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Blazor; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Scheduler.Blazor.Components.Models; 4 | using DevExpress.ExpressApp.Scheduler.Blazor.Editors; 5 | using OutlookInspired.Module.BusinessObjects; 6 | 7 | namespace OutlookInspired.Blazor.Server.Features.Evaluations{ 8 | public class SchedulerGroupTypeController:ObjectViewController{ 9 | protected override void OnViewControlsCreated(){ 10 | base.OnViewControlsCreated(); 11 | if (View.Editor is not SchedulerListEditor editor)return; 12 | ((DxSchedulerModel)editor.Control).GroupType = SchedulerGroupType.None; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/Products/ProductLayoutViewController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using OutlookInspired.Blazor.Server.Editors.LayoutView; 3 | using OutlookInspired.Module.BusinessObjects; 4 | 5 | namespace OutlookInspired.Blazor.Server.Features.Products{ 6 | public class ProductLayoutViewController:ObjectViewController{ 7 | public ProductLayoutViewController() => TargetViewId = Product.LayoutViewListView; 8 | 9 | protected override void OnViewControlsCreated(){ 10 | base.OnViewControlsCreated(); 11 | var model = ((LayoutViewListEditor)View.Editor).Control; 12 | model.ImageSelector = o => ((Product)o).PrimaryImage.Data; 13 | model.HeaderSelector = o => ((Product)o).Name; 14 | model.InfoItemsSelector = o => { 15 | var product = ((Product)o); 16 | return new Dictionary{ 17 | { "COST", product.Cost.ToString("C") }, 18 | { "SALE PRICE", product.SalePrice.ToString("C") } }; 19 | }; 20 | model.FooterSelector = o => ((Product)o).DescriptionString; 21 | } 22 | 23 | } 24 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/ViewFilter/ViewFilterDeleteController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Actions; 3 | using DevExpress.ExpressApp.SystemModule; 4 | using DevExpress.ExpressApp.Utils; 5 | using DevExpress.Persistent.Base; 6 | 7 | namespace OutlookInspired.Blazor.Server.Features.ViewFilter{ 8 | public class ViewFilterDeleteController:ObjectViewController{ 9 | private readonly SimpleAction _simpleAction; 10 | private SimpleAction _deleteAction; 11 | 12 | public ViewFilterDeleteController(){ 13 | _simpleAction = new SimpleAction(this, "DeleteViewFilter", PredefinedCategory.ObjectsCreation){ 14 | Caption = "Delete", SelectionDependencyType = SelectionDependencyType.RequireMultipleObjects, 15 | ImageName = "Delete" 16 | }; 17 | _simpleAction.Executed += (_, _) => _deleteAction.DoExecute(); 18 | } 19 | 20 | protected override void OnDeactivated(){ 21 | base.OnDeactivated(); 22 | _deleteAction.Active.ResultValueChanged-=ActiveOnResultValueChanged; 23 | _deleteAction.Enabled.ResultValueChanged-=EnabledOnResultValueChanged; 24 | } 25 | 26 | protected override void OnActivated(){ 27 | base.OnActivated(); 28 | _deleteAction = Frame.GetController().DeleteAction; 29 | _deleteAction.Active.ResultValueChanged+=ActiveOnResultValueChanged; 30 | _deleteAction.Enabled.ResultValueChanged+=EnabledOnResultValueChanged; 31 | } 32 | 33 | private void EnabledOnResultValueChanged(object sender, BoolValueChangedEventArgs e) => _simpleAction.Enabled[nameof(ViewFilterDeleteController)] = e.NewValue; 34 | 35 | private void ActiveOnResultValueChanged(object sender, BoolValueChangedEventArgs e) => _simpleAction.Active[nameof(ViewFilterDeleteController)] = e.NewValue; 36 | } 37 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Features/WelcomeController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using OutlookInspired.Blazor.Server.Editors.PdfViewer; 3 | using OutlookInspired.Module.BusinessObjects; 4 | 5 | namespace OutlookInspired.Blazor.Server.Features { 6 | public class WelcomeController : ObjectViewController { 7 | protected override void OnActivated() { 8 | base.OnActivated(); 9 | View.CustomizeViewItemControl(this, item => { 10 | item.ComponentModel.CssClass = "welcome-pdf-viewer"; 11 | item.ComponentModel.IsSinglePagePreview = true; 12 | }); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Images/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Folder Description 2 | 3 | The "Images" project folder is intended for storing custom image files. 4 | 5 | 6 | Relevant Documentation 7 | 8 | Add and Override Images 9 | https://docs.devexpress.com/eXpressAppFramework/112792 10 | 11 | Assign a Custom Image 12 | https://docs.devexpress.com/eXpressAppFramework/112744 13 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:65201", 7 | "sslPort": 44318 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "OutlookInspired.Blazor.Server": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5010;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Project Description 2 | 3 | This project implements an ASP.NET Core Blazor Server application (https://docs.microsoft.com/en-us/aspnet/core/blazor/). 4 | The root project folder contains the BlazorApplication.cs file with the class that inherits 5 | BlazorApplication. This class allows you to view and customize application components: referenced modules, 6 | security settings, data connection. Additionally, the root folder contains 7 | Application Model difference files (XAFML files) that keep settings 8 | specific to the current application. Difference files can be customized in code 9 | or in the Model Editor. 10 | The appsettings.json file contains database connection, logging, and theme settings (https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration). 11 | 12 | 13 | Relevant Documentation 14 | 15 | Application Solution Components 16 | https://docs.devexpress.com/eXpressAppFramework/112569 17 | 18 | Debugging, Testing and Error Handling 19 | https://docs.devexpress.com/eXpressAppFramework/112572 20 | 21 | XafApplication Class 22 | https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.XafApplication 23 | 24 | Application Model (UI Settings Storage) 25 | https://docs.devexpress.com/eXpressAppFramework/112579 26 | 27 | Model Editor 28 | https://docs.devexpress.com/eXpressAppFramework/112582 29 | 30 | ASP.NET Core Blazor UI 31 | https://docs.devexpress.com/eXpressAppFramework/401675/overview/supported-ui-platforms#aspnet-core-blazor-ui 32 | 33 | Frequently Asked Questions - Blazor UI (FAQ) 34 | https://docs.devexpress.com/eXpressAppFramework/403277/support-qa-troubleshooting/frequently-asked-questions-blazor-faq 35 | 36 | Backend WebApi Service 37 | https://docs.devexpress.com/eXpressAppFramework/403394/backend-web-api-service 38 | 39 | XAF Community Extensions 40 | https://www.devexpress.com/products/net/application_framework/#extensions -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Services/CircuitHandlerProxy.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Blazor.Services; 2 | using Microsoft.AspNetCore.Components.Server.Circuits; 3 | 4 | namespace OutlookInspired.Blazor.Server.Services; 5 | 6 | internal class CircuitHandlerProxy(IScopedCircuitHandler scopedCircuitHandler) : CircuitHandler{ 7 | public override Task OnCircuitOpenedAsync(Circuit circuit, CancellationToken cancellationToken) 8 | => scopedCircuitHandler.OnCircuitOpenedAsync(cancellationToken); 9 | 10 | public override Task OnConnectionUpAsync(Circuit circuit, CancellationToken cancellationToken) 11 | => scopedCircuitHandler.OnConnectionUpAsync(cancellationToken); 12 | 13 | public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken cancellationToken) 14 | => scopedCircuitHandler.OnCircuitClosedAsync(cancellationToken); 15 | 16 | public override Task OnConnectionDownAsync(Circuit circuit, CancellationToken cancellationToken) 17 | => scopedCircuitHandler.OnConnectionDownAsync(cancellationToken); 18 | } 19 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/Services/ProxyHubConnectionHandler.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Blazor.Services; 2 | using Microsoft.AspNetCore.Connections; 3 | using Microsoft.AspNetCore.SignalR; 4 | using Microsoft.Extensions.Options; 5 | 6 | namespace OutlookInspired.Blazor.Server.Services.Internal; 7 | 8 | internal class ProxyHubConnectionHandler : HubConnectionHandler where THub : Hub { 9 | private readonly IValueManagerStorageContainerInitializer _storageContainerInitializer; 10 | public ProxyHubConnectionHandler( 11 | HubLifetimeManager lifetimeManager, 12 | IHubProtocolResolver protocolResolver, 13 | IOptions globalHubOptions, 14 | IOptions> hubOptions, 15 | ILoggerFactory loggerFactory, 16 | IUserIdProvider userIdProvider, 17 | IServiceScopeFactory serviceScopeFactory, 18 | IValueManagerStorageContainerInitializer storageContainerAccessor) 19 | : base(lifetimeManager, protocolResolver, globalHubOptions, hubOptions, loggerFactory, userIdProvider, serviceScopeFactory) { 20 | _storageContainerInitializer = storageContainerAccessor; 21 | } 22 | 23 | public override Task OnConnectedAsync(ConnectionContext connection) { 24 | _storageContainerInitializer.Initialize(); 25 | return base.OnConnectedAsync(connection); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using Microsoft.AspNetCore.Authorization 3 | @using Microsoft.AspNetCore.Components.Authorization 4 | @using Microsoft.AspNetCore.Components.Forms 5 | @using Microsoft.AspNetCore.Components.Routing 6 | @using Microsoft.AspNetCore.Components.Web 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.JSInterop 9 | @using DevExpress.Blazor 10 | @using DevExpress.ExpressApp.Blazor.Components 11 | @using OutlookInspired.Blazor.Server 12 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "DetailedErrors": true, 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft": "Warning", 7 | "Microsoft.Hosting.Lifetime": "Information", 8 | "DevExpress.ExpressApp": "Information" 9 | } 10 | }, 11 | "DevExpress": { 12 | "ExpressApp": { 13 | "EnableDiagnosticActions": false 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "ConnectionString": "EFCoreProvider=SQLite;Data Source=..\\..\\data\\OutlookInspired_Service.db", 4 | "EasyTestConnectionString": "EFCoreProvider=SQLite;Data Source=..\\..\\data\\OutlookInspired_Service_EasyTest.db" 5 | }, 6 | "Logging": { 7 | "LogLevel": { 8 | "Default": "Information", 9 | "Microsoft": "Warning", 10 | "Microsoft.Hosting.Lifetime": "Information", 11 | "DevExpress.ExpressApp": "Information" 12 | } 13 | }, 14 | "AllowedHosts": "*", 15 | "DevExpress": { 16 | "ExpressApp": { 17 | "Languages": "en-US;", 18 | "ShowLanguageSwitcher": false, 19 | "ThemeSwitcher": { 20 | "DefaultItemName": "Office White", // This line is changed according to the following BC: https://supportcenter.devexpress.com/internal/ticket/details/t1090666, 21 | "ShowSizeModeSwitcher": false, 22 | "Groups": [ 23 | { 24 | "Caption": "DevExpress Themes", 25 | "Items": [ 26 | { 27 | "Caption": "Blazing Dark", 28 | "Url": "_content/DevExpress.Blazor.Themes/blazing-dark.bs5.min.css", 29 | "Color": "#46444a" 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | } 4 | 5 | app { 6 | display: block; 7 | height: 100%; 8 | } 9 | 10 | .header-logo { 11 | flex-shrink: 0; 12 | background-color: currentColor; 13 | -webkit-mask: url('../images/Logo.svg'); 14 | mask: url('../images/Logo.svg'); 15 | -webkit-mask-position: center; 16 | mask-position: center; 17 | -webkit-mask-repeat: no-repeat; 18 | mask-repeat: no-repeat; 19 | width: 180px; 20 | height: 24px; 21 | } 22 | 23 | #blazor-error-ui { 24 | background: inherit; 25 | bottom: 0; 26 | display: none; 27 | position: fixed; 28 | width: 100%; 29 | height: 100%; 30 | z-index: 100001; 31 | } 32 | 33 | .welcome-pdf-viewer { 34 | width: 100%; 35 | height: 500px; 36 | } 37 | 38 | .welcome-pdf-viewer .dxbrv-toolbar { 39 | height: 2rem; 40 | } 41 | 42 | .pe-pdf-viewer .dxbrv-toolbar { 43 | height: 2rem; 44 | } 45 | 46 | .pe-pdf-viewer { 47 | width: 100%; 48 | height: 100vh; 49 | } 50 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Blazor.Server/wwwroot/favicon.ico -------------------------------------------------------------------------------- /CS/OutlookInspired.Blazor.Server/wwwroot/images/SplashScreen.svg: -------------------------------------------------------------------------------- 1 | 3 | 6 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /CS/OutlookInspired.MiddleTier/JWT/JwtTokenProviderService.cs: -------------------------------------------------------------------------------- 1 | using System.IdentityModel.Tokens.Jwt; 2 | using System.Runtime.ExceptionServices; 3 | using System.Security.Claims; 4 | using System.Text; 5 | using DevExpress.ExpressApp; 6 | using DevExpress.ExpressApp.Security; 7 | using DevExpress.ExpressApp.Security.Authentication.ClientServer; 8 | using Microsoft.IdentityModel.Tokens; 9 | using DevExpress.ExpressApp.MultiTenancy; 10 | using DevExpress.ExpressApp.MultiTenancy.Internal; 11 | 12 | namespace OutlookInspired.WebApi.JWT; 13 | 14 | public class JwtTokenProviderService : IAuthenticationTokenProvider { 15 | readonly SignInManager signInManager; 16 | readonly IConfiguration configuration; 17 | 18 | public JwtTokenProviderService(SignInManager signInManager, IConfiguration configuration) { 19 | this.signInManager = signInManager; 20 | this.configuration = configuration; 21 | } 22 | public string Authenticate(object logonParameters) { 23 | var result = signInManager.AuthenticateByLogonParameters(logonParameters); 24 | if(result.Succeeded) { 25 | var issuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Authentication:Jwt:IssuerSigningKey"])); 26 | var token = new JwtSecurityToken( 27 | //issuer: configuration["Authentication:Jwt:Issuer"], 28 | //audience: configuration["Authentication:Jwt:Audience"], 29 | claims: result.Principal.Claims, 30 | expires: DateTime.Now.AddDays(2), 31 | signingCredentials: new SigningCredentials(issuerSigningKey, SecurityAlgorithms.HmacSha256) 32 | ); 33 | return new JwtSecurityTokenHandler().WriteToken(token); 34 | } 35 | if(result.Error is IUserFriendlyException) { 36 | ExceptionDispatchInfo.Throw(result.Error); 37 | } 38 | throw new AuthenticationException("Internal server error"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /CS/OutlookInspired.MiddleTier/JWT/WebApiAuthenticationController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Security; 3 | using DevExpress.ExpressApp.Security.Authentication; 4 | using DevExpress.ExpressApp.Security.Authentication.ClientServer; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Swashbuckle.AspNetCore.Annotations; 7 | 8 | namespace OutlookInspired.WebApi.JWT; 9 | 10 | [ApiController] 11 | [Route("api/[controller]")] 12 | // This is a JWT authentication service sample. 13 | public class AuthenticationController : ControllerBase { 14 | readonly IAuthenticationTokenProvider tokenProvider; 15 | public AuthenticationController(IAuthenticationTokenProvider tokenProvider) { 16 | this.tokenProvider = tokenProvider; 17 | } 18 | [HttpPost("Authenticate")] 19 | [SwaggerOperation("Checks if the user with the specified logon parameters exists in the database. If it does, authenticates this user.", "Refer to the following help topic for more information on authentication methods in the XAF Security System: Authentication.")] 20 | public IActionResult Authenticate( 21 | [FromBody] 22 | [SwaggerRequestBody(@"For example:
{ ""userName"": ""Admin"", ""password"": """" }")] 23 | AuthenticationStandardLogonParameters logonParameters 24 | ) { 25 | try { 26 | return Ok(tokenProvider.Authenticate(logonParameters)); 27 | } 28 | catch(AuthenticationException ex) { 29 | return Unauthorized(ex.GetJson()); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CS/OutlookInspired.MiddleTier/OutlookInspired.MiddleTier.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | false 5 | false 6 | 1.0.* 7 | 1.0.0.0 8 | Debug;Release;EasyTest 9 | enable 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /CS/OutlookInspired.MiddleTier/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:5000", 8 | "sslPort": 0 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "swagger", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "OutlookInspired.MiddleTier": { 21 | "commandName": "Project", 22 | "dotnetRunMessages": "true", 23 | "launchBrowser": true, 24 | "launchUrl": "swagger", 25 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.MiddleTier/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Project Description 2 | 3 | This project implements an ASP.NET Core Web API application (https://docs.devexpress.com/eXpressAppFramework/403394/backend-web-api-service). 4 | The appsettings.json file contains database connection, logging, and authentication settings (https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration). 5 | 6 | YOUR FEEDBACK MATTERS 7 | Please tell us how our Web API Service works for you: https://www.devexpress.com/go/XAF_WebAPI_Feedback.aspx - THANKS! 8 | 9 | Relevant Documentation 10 | 11 | Backend Web API Service 12 | https://docs.devexpress.com/eXpressAppFramework/403394/backend-web-api-service 13 | 14 | Overview 15 | https://www.devexpress.com/products/net/application_framework/security-web-api-service.xml -------------------------------------------------------------------------------- /CS/OutlookInspired.MiddleTier/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "DetailedErrors": true, 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft": "Warning", 7 | "Microsoft.Hosting.Lifetime": "Information", 8 | "DevExpress.ExpressApp": "Information" 9 | } 10 | }, 11 | "DevExpress": { 12 | "ExpressApp": { 13 | "EnableDiagnosticActions": false 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.MiddleTier/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "ConnectionString": "EFCoreProvider=SQLite;Data Source=..\\..\\data\\OutlookInspired_Service.db", 4 | "EasyTestConnectionString": "EFCoreProvider=SQLite;Data Source=..\\..\\data\\OutlookInspired_Service_EasyTest.db" 5 | }, 6 | "Authentication": { 7 | "Jwt": { 8 | // For more information, refer to the following topic: Configure the JWT Authentication for the Web API https://docs.devexpress.com/eXpressAppFramework/403504 9 | "Issuer": "My", 10 | "Audience": "http://localhost:4200", 11 | // The debug secret key. You should store sensitive settings in dedicated secret storage. For more information, refer to the following topic: https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-7.0&tabs=windows. 12 | "IssuerSigningKey": "950315be-6674-43c4-8f84-cd060f5bddc3" 13 | }, 14 | }, 15 | "Logging": { 16 | "LogLevel": { 17 | "Default": "Information", 18 | "Microsoft": "Warning", 19 | "Microsoft.Hosting.Lifetime": "Information", 20 | "DevExpress.ExpressApp": "Information" 21 | } 22 | }, 23 | "AllowedHosts": "*", 24 | "DevExpress": { 25 | "ExpressApp": { 26 | "Languages": "en-US;" 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Attributes/Appearance/DeactivateActionAttribute.cs: -------------------------------------------------------------------------------- 1 | using Aqua.EnumerableExtensions; 2 | using DevExpress.ExpressApp.ConditionalAppearance; 3 | using DevExpress.ExpressApp.Editors; 4 | 5 | namespace OutlookInspired.Module.Attributes.Appearance{ 6 | public class DeactivateActionAttribute:AppearanceAttribute{ 7 | public DeactivateActionAttribute(params string[] actions) : 8 | base($"Deactivate {actions.StringJoin(" ")}",DevExpress.ExpressApp.ConditionalAppearance.AppearanceItemType.Action,"1=1"){ 9 | Visibility=ViewItemVisibility.Hide; 10 | TargetItems = actions.StringJoin(";"); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Attributes/Appearance/ForbidCRUDAttribute.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.SystemModule; 2 | 3 | namespace OutlookInspired.Module.Attributes.Appearance{ 4 | public class ForbidCRUDAttribute:DeactivateActionAttribute{ 5 | public ForbidCRUDAttribute(params string[] contexts) : base("New","Save","SaveAndClose","SaveAndNew","Delete","Cancel") 6 | => Context = string.Join(";", contexts); 7 | public ForbidCRUDAttribute(bool forbidProcessSelectedObject,params string[] contexts) : this(contexts){ 8 | if (forbidProcessSelectedObject){ 9 | TargetItems += $";{ListViewProcessCurrentObjectController.ListViewShowObjectActionId}".TrimStart(';'); 10 | } 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Attributes/Appearance/ForbidDeleteAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace OutlookInspired.Module.Attributes.Appearance{ 2 | public class ForbidDeleteAttribute:DeactivateActionAttribute{ 3 | public ForbidDeleteAttribute(params string[] contexts) : base("Delete") 4 | => Context = string.Join(";", contexts); 5 | } 6 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Attributes/Appearance/ForbidNavigation.cs: -------------------------------------------------------------------------------- 1 | namespace OutlookInspired.Module.Attributes.Appearance{ 2 | public class ForbidNavigation:DeactivateActionAttribute{ 3 | public ForbidNavigation() : base("PreviousObject","NextObject"){ 4 | 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Attributes/FontSizeDeltaAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace OutlookInspired.Module.Attributes{ 2 | [AttributeUsage(AttributeTargets.Property)] 3 | public class FontSizeDeltaAttribute(int delta) : Attribute{ 4 | public int Delta{ get; } = delta; 5 | 6 | public string Style(){ 7 | var size = Delta == 8 ? "1.8" : "1.2"; 8 | return $"line-height: {size}rem;font-size: {size}rem"; 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Attributes/Validation/EmailAddressAttribute.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Persistent.Validation; 2 | 3 | namespace OutlookInspired.Module.Attributes.Validation{ 4 | public class EmailAddressAttribute() 5 | : RuleRegularExpressionAttribute(@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"); 6 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Attributes/Validation/PhoneAttribute.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Persistent.Validation; 2 | 3 | namespace OutlookInspired.Module.Attributes.Validation{ 4 | public class PhoneAttribute:RuleRegularExpressionAttribute{ 5 | public PhoneAttribute():base(@"^\(\d{3}\)\s\d{3}-\d{4}$") => CustomMessageTemplate = "{TargetPropertyName} must match the pattern (123) 456-7890"; 6 | } 7 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Attributes/Validation/UrlAttribute.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Persistent.Validation; 2 | 3 | namespace OutlookInspired.Module.Attributes.Validation{ 4 | public class UrlAttribute() 5 | : RuleRegularExpressionAttribute("^(http(s)?://)?([\\w-]+\\.)+[\\w-]+(/[\\w- ;,./?%&=]*)?$"); 6 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Attributes/Validation/ZipCodeAttribute.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Persistent.Validation; 2 | 3 | namespace OutlookInspired.Module.Attributes.Validation{ 4 | public class ZipCodeAttribute:RuleRegularExpressionAttribute{ 5 | public ZipCodeAttribute() : base(@"^[0-9][0-9][0-9][0-9][0-9]$") => CustomMessageTemplate = "Not a valid ZIP code."; 6 | } 7 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/ApplicationUser.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel; 3 | using DevExpress.ExpressApp; 4 | using DevExpress.ExpressApp.ConditionalAppearance; 5 | using DevExpress.ExpressApp.Editors; 6 | using DevExpress.ExpressApp.Security; 7 | using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy; 8 | 9 | namespace OutlookInspired.Module.BusinessObjects; 10 | [DefaultProperty(nameof(UserName))] 11 | public class ApplicationUser : PermissionPolicyUser, ISecurityUserWithLoginInfo,ISecurityUserLockout { 12 | [Browsable(false)] 13 | public virtual int AccessFailedCount { get; set; } 14 | 15 | [Browsable(false)] 16 | public virtual DateTime LockoutEnd { get; set; } 17 | [Browsable(false)] 18 | [DevExpress.ExpressApp.DC.Aggregated] 19 | public virtual IList UserLogins { get; set; }= new ObservableCollection(); 20 | 21 | IEnumerable IOAuthSecurityUser.UserLogins => UserLogins; 22 | 23 | ISecurityUserLoginInfo ISecurityUserWithLoginInfo.CreateUserLoginInfo(string loginProviderName, string providerUserKey) { 24 | var result = ((IObjectSpaceLink)this).ObjectSpace.CreateObject(); 25 | result.LoginProviderName = loginProviderName; 26 | result.ProviderUserKey = providerUserKey; 27 | result.User = this; 28 | return result; 29 | } 30 | [Browsable(false)] 31 | public bool IsAdmin => Roles.Any(role => role.IsAdministrative); 32 | [Appearance("Hide for Admin",AppearanceItemType.ViewItem, nameof(IsAdmin),Visibility = ViewItemVisibility.Hide)] 33 | public virtual Employee Employee { get; set; } 34 | } 35 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/ApplicationUserLoginInfo.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | using DevExpress.ExpressApp.ConditionalAppearance; 5 | using DevExpress.ExpressApp.Security; 6 | using DevExpress.Persistent.Validation; 7 | 8 | namespace OutlookInspired.Module.BusinessObjects; 9 | 10 | [Table("PermissionPolicyUserLoginInfo")] 11 | public class ApplicationUserLoginInfo : ISecurityUserLoginInfo { 12 | [Browsable(false)] 13 | public virtual Guid ID { get; protected set; } 14 | [Appearance("PasswordProvider", Enabled = false, Criteria = "!(IsNewObject(this)) and LoginProviderName == '" + SecurityDefaults.PasswordAuthentication + "'", Context = "DetailView")] 15 | [MaxLength(100)] 16 | public virtual string LoginProviderName { get; set; } 17 | [Appearance("PasswordProviderUserKey", Enabled = false, Criteria = "!(IsNewObject(this)) and LoginProviderName == '" + SecurityDefaults.PasswordAuthentication + "'", Context = "DetailView")] 18 | [MaxLength(255)] 19 | public virtual string ProviderUserKey { get; set; } 20 | [Browsable(false)] 21 | public virtual Guid UserForeignKey { get; set; } 22 | [RuleRequiredField] 23 | [ForeignKey(nameof(UserForeignKey))] 24 | public virtual ApplicationUser User { get; set; } 25 | object ISecurityUserLoginInfo.User => User; 26 | } 27 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/Crest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using DevExpress.ExpressApp.DC; 4 | using DevExpress.Persistent.Base; 5 | 6 | 7 | namespace OutlookInspired.Module.BusinessObjects{ 8 | [XafDefaultProperty(nameof(CityName))] 9 | [VisibleInReports(false)] 10 | public class Crest:OutlookInspiredBaseObject { 11 | [MaxLength(100)] 12 | public virtual string CityName { get; set; } 13 | [ImageEditor(ListViewImageEditorMode = ImageEditorMode.PictureEdit, 14 | DetailViewImageEditorMode = ImageEditorMode.PictureEdit)] 15 | public virtual byte[] SmallImage { get; set; } 16 | [ImageEditor(ListViewImageEditorMode = ImageEditorMode.PictureEdit, 17 | DetailViewImageEditorMode = ImageEditorMode.PictureEdit)] 18 | [XafDisplayName("Large")][HideInUI(HideInUI.ListView)][VisibleInLookupListView(false)] 19 | public virtual byte[] LargeImage { get; set; } 20 | 21 | public virtual ObservableCollection CustomerStores{ get; set; } = new(); 22 | 23 | } 24 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/CustomerCommunication.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using DevExpress.Persistent.Base; 3 | 4 | namespace OutlookInspired.Module.BusinessObjects{ 5 | [ImageName("ProductQuickComparisons")] 6 | public class CustomerCommunication:OutlookInspiredBaseObject { 7 | public virtual Employee Employee { get; set; } 8 | public virtual CustomerEmployee CustomerEmployee { get; set; } 9 | public virtual DateTime Date { get; set; } 10 | [MaxLength(100)] 11 | public virtual string Type { get; set; } 12 | [EditorAlias(EditorAliases.DxHtmlPropertyEditor)] 13 | public virtual byte[] Purpose { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/CustomerEmployee.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel; 3 | using System.ComponentModel.DataAnnotations; 4 | using DevExpress.ExpressApp.DC; 5 | using DevExpress.Persistent.Base; 6 | using DevExpress.Persistent.Validation; 7 | 8 | namespace OutlookInspired.Module.BusinessObjects { 9 | [DefaultProperty(nameof(FullName))] 10 | [ImageName("BO_Employee")] 11 | public class CustomerEmployee :OutlookInspiredBaseObject{ 12 | [RuleRequiredField][MaxLength(100)] 13 | public virtual string FirstName { get; set; } 14 | [RuleRequiredField][MaxLength(100)] 15 | public virtual string LastName { get; set; } 16 | [PersistentAlias("Concat(" +nameof(FirstName) + ", ' ', " +nameof(LastName)+ ")")] 17 | public string FullName => (string)EvaluateAlias(); 18 | 19 | public virtual PersonPrefix Prefix { get; set; } 20 | [RuleRequiredField, Attributes.Validation.Phone][MaxLength(100)] 21 | public virtual string MobilePhone { get; set; } 22 | [RuleRequiredField, Attributes.Validation.EmailAddress][MaxLength(255)] 23 | public virtual string Email { get; set; } 24 | public virtual Picture Picture { get; set; } 25 | 26 | public virtual Customer Customer { get; set; } 27 | [Browsable(false)] 28 | public virtual Guid CustomerId { get; set; } 29 | 30 | public virtual CustomerStore CustomerStore { get; set; } 31 | [MaxLength(100)] 32 | public virtual string Position { get; set; } 33 | public virtual bool IsPurchaseAuthority { get; set; } 34 | [Aggregated] 35 | public virtual ObservableCollection CustomerCommunications{ get; set; } = new(); 36 | 37 | 38 | } 39 | public enum PersonPrefix { 40 | [ImageName("Doctor")] 41 | Dr, 42 | [ImageName("Mr")] 43 | Mr, 44 | [ImageName("Ms")] 45 | Ms, 46 | [ImageName("Miss")] 47 | Miss, 48 | [ImageName("Mrs")] 49 | Mrs 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/CustomerStore.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | using DevExpress.ExpressApp.DC; 5 | using DevExpress.Persistent.Base; 6 | using OutlookInspired.Module.Attributes.Validation; 7 | 8 | 9 | namespace OutlookInspired.Module.BusinessObjects{ 10 | [XafDefaultProperty(nameof(Crest))][ImageName("Shopping_Store")] 11 | public class CustomerStore :OutlookInspiredBaseObject,IMapsMarker{ 12 | [MaxLength(255)] 13 | public virtual string Line { get; set; } 14 | [MaxLength(100)] 15 | public virtual string City { get; set; } 16 | public virtual StateEnum State { get; set; } 17 | [ZipCode][MaxLength(20)] 18 | public virtual string ZipCode { get; set; } 19 | public virtual double Latitude { get; set; } 20 | public virtual double Longitude { get; set; } 21 | public virtual Customer Customer { get; set; } 22 | [Attributes.Validation.Phone][MaxLength(20)] 23 | public virtual string Phone { get; set; } 24 | [Attributes.Validation.Phone][MaxLength(20)] 25 | public virtual string Fax { get; set; } 26 | public virtual int TotalEmployees { get; set; } 27 | public virtual int SquereFootage { get; set; } 28 | 29 | [Column(TypeName = CurrencyType)] 30 | public virtual decimal AnnualSales { get; set; } 31 | public virtual Crest Crest { get; set; } 32 | [MaxLength(255)] 33 | public virtual string Location { get; set; } 34 | [Aggregated] 35 | public virtual ObservableCollection CustomerEmployees{ get; set; } = new(); 36 | [Aggregated] 37 | public virtual ObservableCollection Orders{ get; set; } = new(); 38 | [Aggregated] 39 | public virtual ObservableCollection Quotes{ get; set; } = new(); 40 | string IBaseMapsMarker.Title => Location; 41 | 42 | } 43 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/Opportunity.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Data; 4 | using DevExpress.ExpressApp.DC; 5 | using DevExpress.Persistent.Base; 6 | 7 | namespace OutlookInspired.Module.BusinessObjects{ 8 | [DomainComponent][ImageName("BO_Quote")] 9 | public class Opportunity:IObjectSpaceLink{ 10 | 11 | [Key][Browsable(false)] 12 | public int ID{ get; set; } 13 | public Stage Stage{ get; set; } 14 | 15 | IObjectSpace IObjectSpaceLink.ObjectSpace{ get; set; } 16 | public decimal Value{ get; set; } 17 | public DateTime Date{ get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/OrderItem.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | using DevExpress.Persistent.Base; 4 | using OutlookInspired.Module.Attributes.Appearance; 5 | using OutlookInspired.Module.Features.CloneView; 6 | 7 | 8 | namespace OutlookInspired.Module.BusinessObjects{ 9 | [VisibleInReports(true)][ImageName("BO_Sale")] 10 | [CloneView(CloneViewType.ListView,RecentOrderItemsListView )] 11 | [ForbidCRUD(true,RecentOrderItemsListView,"Product_OrderItems_ListView")] 12 | public class OrderItem :OutlookInspiredBaseObject{ 13 | public const string RecentOrderItemsListView = "Recent_OrderItems_ListView"; 14 | 15 | public virtual Order Order { get; set; } 16 | [Browsable(false)] 17 | public virtual Guid? OrderID { get; set; } 18 | public virtual Product Product{ get; set; } 19 | [Browsable(false)] 20 | public virtual Guid? ProductID { get; set; } 21 | public virtual int ProductUnits { get; set; } 22 | [Column(TypeName = CurrencyType)] 23 | public virtual decimal ProductPrice { get; set; } 24 | [Column(TypeName = CurrencyType)] 25 | public virtual decimal Discount { get; set; } 26 | [Column(TypeName = CurrencyType)] 27 | public virtual decimal Total { get; set; } 28 | } 29 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/OutlookInspiredBaseObject.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | using System.ComponentModel; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | using DevExpress.ExpressApp; 6 | using DevExpress.Persistent.BaseImpl.EF; 7 | using OutlookInspired.Module.Attributes.Appearance; 8 | 9 | namespace OutlookInspired.Module.BusinessObjects{ 10 | [DeactivateAction("ShowInDocument",Context = "Any;Employee_ListView;")] 11 | [DeactivateAction("Save", "SaveAndClose", "SaveAndNew", "ShowAllContexts", "NextObject", "PreviousObject", 12 | Context = Customer.GridViewDetailView + ";" + Customer.LayoutViewDetailView )] 13 | [DeactivateAction("OpenObject", 14 | Context = Customer.MapsDetailView + ";" + Employee.MapsDetailView + ";" + Product.MapsDetailView + ";" + 15 | Order.MapsDetailView + ";")] 16 | public abstract class OutlookInspiredBaseObject:BaseObject{ 17 | protected const string CurrencyType = "decimal(18, 2)"; 18 | [Browsable(false)] 19 | public virtual long IdInt64{ get; set; } 20 | 21 | [NotMapped][Browsable(false)] 22 | public new IObjectSpace ObjectSpace{ 23 | get => base.ObjectSpace; 24 | set => base.ObjectSpace=value; 25 | } 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/Period.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Persistent.Base; 2 | 3 | namespace OutlookInspired.Module.BusinessObjects{ 4 | public enum Period{ 5 | [ImageName("CustomerQuickSales")] 6 | ThisMonth, 7 | [ImageName("SalesAnalysis")] 8 | ThisYear, 9 | [ImageName("Demo_SalesOverview")] 10 | Lifetime, 11 | FixedDate, 12 | } 13 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/Picture.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | using System.Collections.ObjectModel; 4 | using DevExpress.Persistent.Base; 5 | 6 | namespace OutlookInspired.Module.BusinessObjects; 7 | public class Picture :OutlookInspiredBaseObject{ 8 | [ImageEditor(ListViewImageEditorMode = ImageEditorMode.PictureEdit, 9 | DetailViewImageEditorMode = ImageEditorMode.PictureEdit,ImageSizeMode = ImageSizeMode.Zoom)] 10 | public virtual byte[] Data { get; set; } 11 | 12 | public virtual ObservableCollection Employees{ get; set; } = new(); 13 | public virtual ObservableCollection CustomerEmployees{ get; set; } = new(); 14 | public virtual ObservableCollection Products{ get; set; } = new(); 15 | public virtual ObservableCollection ProductImages{ get; set; } = new(); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/Probation.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | using System.Collections.ObjectModel; 4 | using System.ComponentModel.DataAnnotations; 5 | 6 | namespace OutlookInspired.Module.BusinessObjects{ 7 | public class Probation:OutlookInspiredBaseObject { 8 | [MaxLength(100)] 9 | public virtual string Reason { get; set; } 10 | public virtual ObservableCollection Employees{ get; set; } = new(); 11 | } 12 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/ProductCatalog.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | using System.ComponentModel; 4 | 5 | namespace OutlookInspired.Module.BusinessObjects{ 6 | public class ProductCatalog :OutlookInspiredBaseObject{ 7 | public virtual Product Product { get; set; } 8 | [Browsable(false)] 9 | public virtual Guid? ProductId { get; set; } 10 | public virtual byte[] PDF { get; set; } 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/ProductImage.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | namespace OutlookInspired.Module.BusinessObjects{ 4 | public class ProductImage :OutlookInspiredBaseObject{ 5 | public virtual Picture Picture { get; set; } 6 | public virtual Product Product { get; set; } 7 | public virtual Guid? ProductId { get; set; } 8 | 9 | } 10 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/QuoteAnalysis.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Data; 2 | using DevExpress.ExpressApp.DC; 3 | using OutlookInspired.Module.Features; 4 | 5 | namespace OutlookInspired.Module.BusinessObjects{ 6 | [DomainComponent] 7 | public class QuoteAnalysis:IViewFilter{ 8 | [Key] 9 | public int ID{ get; set; } 10 | public StateEnum State { get; set; } 11 | public string City { get; set; } 12 | public DateTime Date { get; set; } 13 | public decimal Total { get; set; } 14 | public double Opportunity { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/QuoteItem.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | using DevExpress.Persistent.Base; 4 | 5 | 6 | namespace OutlookInspired.Module.BusinessObjects{ 7 | [ImageName("Shopping_Sales")] 8 | // [CloneView(CloneViewType.ListView, MapsListView)] 9 | public class QuoteItem :OutlookInspiredBaseObject{ 10 | // public const string MapsListView = "QuoteItem_ListView_Maps"; 11 | public virtual Quote Quote { get; set; } 12 | [Browsable(false)] 13 | public virtual Guid? QuoteID { get; set; } 14 | public virtual Product Product { get; set; } 15 | [Browsable(false)] 16 | public virtual Guid? ProductId { get; set; } 17 | public virtual int ProductUnits { get; set; } 18 | [Column(TypeName = CurrencyType)] 19 | public virtual decimal ProductPrice { get; set; } 20 | [Column(TypeName = "decimal(18, 2)")] 21 | public virtual decimal Discount { get; set; } 22 | [Column(TypeName = "decimal(18, 2)")] 23 | public virtual decimal Total { get; set; } 24 | 25 | 26 | 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/State.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using DevExpress.Persistent.Base; 4 | 5 | 6 | namespace OutlookInspired.Module.BusinessObjects{ 7 | [DefaultProperty(nameof(LongName))] 8 | public class State:OutlookInspiredBaseObject{ 9 | [MaxLength(255)] 10 | public virtual string LongName{ get; set; } 11 | public virtual StateEnum ShortName{ get; set; } 12 | [ImageEditor(ListViewImageEditorMode = ImageEditorMode.PictureEdit, 13 | DetailViewImageEditorMode = ImageEditorMode.PictureEdit)] 14 | public virtual byte[] SmallFlag{ get; set; } 15 | [ImageEditor(ListViewImageEditorMode = ImageEditorMode.PictureEdit, 16 | DetailViewImageEditorMode = ImageEditorMode.PictureEdit)] 17 | public virtual byte[] LargeFlag{ get; set; } 18 | 19 | } 20 | 21 | public enum StateEnum { 22 | CA=1, AR, AL, AK, AZ, CO, CT, DE, DC, FL, GA, HI, ID, IL, IN, IA, KS, KY, LA, ME, MD, MA, MI, MN, MS, MO, MT, NE, NV, NH, NJ, NM, NY, NC, OH, OK, OR, PA, RI, SC, SD, TN, TX, UT, VT, VA, WA, WV, WI, WY, ND 23 | } 24 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/TaskAttachedFile.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Text; 3 | using DevExpress.Persistent.Base; 4 | using DevExpress.Persistent.BaseImpl.EF; 5 | using DevExpress.Persistent.Validation; 6 | 7 | 8 | namespace OutlookInspired.Module.BusinessObjects{ 9 | [ImageName("AttachFile")] 10 | public class TaskAttachedFile :OutlookInspiredBaseObject{ 11 | 12 | public virtual EmployeeTask EmployeeTask { get; set; } 13 | [ExpandObjectMembers(ExpandObjectMembers.Never), RuleRequiredField()] 14 | public virtual FileData File { get; set; } 15 | [Browsable(false)] 16 | public virtual Guid? EmployeeTaskId{ get; set; } 17 | 18 | [EditorAlias(EditorAliases.DxHtmlPropertyEditor)] 19 | public string Preview 20 | => File != null && Path.GetExtension(File.FileName) == ".rtf" ? GetString(File.Content) : null; 21 | 22 | string GetString( byte[] bytes, Encoding encoding = null) 23 | => bytes == null ? null : (encoding ?? Encoding.UTF8).GetString(bytes); 24 | } 25 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/TaxRate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using DevExpress.ExpressApp.Model; 4 | using DevExpress.Persistent.Validation; 5 | 6 | namespace OutlookInspired.Module.BusinessObjects { 7 | [DefaultProperty(nameof(State))] 8 | public class TaxRate : OutlookInspiredBaseObject { 9 | 10 | [RuleUniqueValue("", DefaultContexts.Save)] 11 | public virtual StateEnum State { get; set; } 12 | 13 | [ModelDefault("DisplayFormat", "{0:F2}")] 14 | [ModelDefault("EditMask", "F2")] 15 | public virtual decimal Rate { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/BusinessObjects/Welcome.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.DC; 3 | using DevExpress.Persistent.Base; 4 | using OutlookInspired.Module.Attributes.Appearance; 5 | 6 | namespace OutlookInspired.Module.BusinessObjects{ 7 | [DomainComponent][ForbidCRUD][ForbidNavigation] 8 | [ImageName("About")] 9 | public class Welcome : NonPersistentBaseObject { 10 | public Welcome(){ 11 | var assembly = GetType().Assembly; 12 | About = Bytes(assembly.GetManifestResourceStream(assembly.GetManifestResourceNames().First(s => s.EndsWith("Welcome.pdf")))); 13 | } 14 | 15 | byte[] Bytes( Stream stream){ 16 | if (stream is MemoryStream memoryStream){ 17 | return memoryStream.ToArray(); 18 | } 19 | 20 | using var ms = new MemoryStream(); 21 | stream.CopyTo(ms); 22 | return ms.ToArray(); 23 | } 24 | 25 | 26 | [EditorAlias(EditorAliases.PdfViewerEditor)] 27 | public byte[] About{ get; set; } 28 | } 29 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/DatabaseUpdate/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Folder Description 2 | 3 | The "DatabaseUpdate" project folder is intended for storing code that supplies 4 | initial data (default User objects, etc) and handles a database update when the 5 | application version changes. 6 | 7 | 8 | Relevant Documentation 9 | 10 | Supply Initial Data (EF Core) 11 | https://docs.devexpress.com/eXpressAppFramework/402985 12 | 13 | ModuleUpdater Class 14 | https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Updating.ModuleUpdater 15 | 16 | Application Update 17 | https://docs.devexpress.com/eXpressAppFramework/113239 18 | 19 | Migrations Overview (EF Core) 20 | https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations 21 | 22 | Debugging, Unit and Functional Testing 23 | https://docs.devexpress.com/eXpressAppFramework/112572 24 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/EditorAliases.cs: -------------------------------------------------------------------------------- 1 | namespace OutlookInspired.Module{ 2 | public struct EditorAliases { 3 | 4 | public const string EnumImageOnlyEditor = "EnumImageOnlyEditor"; 5 | public const string PrintLayoutRichTextEditor = "PrintLayoutRichTextEditor"; 6 | public const string PdfViewerEditor = "PdfViewerEditor"; 7 | public const string LabelPropertyEditor = "LabelPropertyEditor"; 8 | public const string HyperLinkPropertyEditor = "HyperLinkPropertyEditor"; 9 | public const string DxHtmlPropertyEditor = "DxHtmlPropertyEditor"; 10 | public const string MapHomeOfficePropertyEditor = "MapHomeOfficePropertyEditor"; 11 | } 12 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/CloneView/CloneViewAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace OutlookInspired.Module.Features.CloneView{ 2 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] 3 | public class CloneViewAttribute(CloneViewType viewType, string viewId) : Attribute{ 4 | public string ViewId{ get; } = viewId; 5 | public CloneViewType ViewType{ get; } = viewType; 6 | public string DetailView{ get; set; } 7 | } 8 | public enum CloneViewType{ 9 | DetailView, 10 | ListView, 11 | LookupListView 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/CloneView/CloneViewUpdater.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Model; 2 | using DevExpress.ExpressApp.Model.Core; 3 | using DevExpress.ExpressApp.Model.NodeGenerators; 4 | 5 | namespace OutlookInspired.Module.Features.CloneView; 6 | public class CloneViewUpdater : ModelNodesGeneratorUpdater { 7 | public override void UpdateNode(ModelNode node){ 8 | foreach (var modelClass in node.Application.BOModel){ 9 | foreach (var attribute in modelClass.TypeInfo.FindAttributes() 10 | .OrderBy(viewAttribute => viewAttribute.ViewType)){ 11 | var modelView = GetModelView(modelClass, attribute.ViewType); 12 | CreateView(modelView, attribute.ViewId, attribute.DetailView); 13 | } 14 | } 15 | } 16 | void CreateView( IModelView source, string viewId,string detailViewId=null) { 17 | var cloneNodeFrom = ((ModelNode)source).Clone(viewId); 18 | if (source is not IModelListView || string.IsNullOrEmpty(detailViewId)) return; 19 | ((IModelListView)cloneNodeFrom).DetailView = source.Application.Views.OfType() 20 | .FirstOrDefault(view => view.Id == detailViewId)??throw new NullReferenceException(detailViewId); 21 | } 22 | 23 | IModelView GetModelView(IModelClass modelClass, CloneViewType viewType) 24 | => viewType == CloneViewType.LookupListView ? modelClass.DefaultLookupListView 25 | : viewType == CloneViewType.DetailView ? modelClass.DefaultDetailView : modelClass.DefaultListView; 26 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Customers/MapCustomerController.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Actions; 4 | using DevExpress.ExpressApp.Model; 5 | using DevExpress.ExpressApp.Templates; 6 | using DevExpress.Persistent.Base; 7 | using OutlookInspired.Module.BusinessObjects; 8 | 9 | namespace OutlookInspired.Module.Features.Customers{ 10 | class MapCustomerController:ObjectViewController{ 11 | public const string MapItActionId = "MapCustomer"; 12 | public MapCustomerController(){ 13 | MapCustomerAction = new PopupWindowShowAction(this, MapItActionId, PredefinedCategory.View){ 14 | ImageName = "MapIt", PaintStyle = ActionItemPaintStyle.Image,SelectionDependencyType = SelectionDependencyType.RequireSingleObject 15 | }; 16 | MapCustomerAction.CustomizePopupWindowParams+=MapCustomerActionOnCustomizePopupWindowParams; 17 | } 18 | 19 | private void MapCustomerActionOnCustomizePopupWindowParams(object sender, CustomizePopupWindowParamsEventArgs e){ 20 | var objectSpace = Application.CreateObjectSpace(typeof(Customer)); 21 | var createdView = Application.CreateDetailView(objectSpace, 22 | (IModelDetailView)Application.Model.Views[Customer.MapsDetailView], false, objectSpace.GetObject(View.CurrentObject)); 23 | e.View = createdView; 24 | e.Size=new Size(1024,768); 25 | } 26 | 27 | public PopupWindowShowAction MapCustomerAction{ get; } 28 | 29 | } 30 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Employees/CommunicationController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Actions; 3 | using DevExpress.ExpressApp.Templates; 4 | 5 | namespace OutlookInspired.Module.Features.Employees{ 6 | public class CommunicationController:ObjectViewController{ 7 | public CommunicationController(){ 8 | NewAction(nameof(BusinessObjects.Employee.HomePhone), "icon-home-phone-16", 9 | _ => throw new UserFriendlyException($"Call {((BusinessObjects.Employee)View.CurrentObject).HomePhone}")); 10 | NewAction(nameof(BusinessObjects.Employee.MobilePhone), "icon-mobile-phone-16", 11 | _ => throw new UserFriendlyException($"Call {((BusinessObjects.Employee)View.CurrentObject).MobilePhone}")); 12 | NewAction(nameof(BusinessObjects.Employee.Skype), "Skype", 13 | _ => throw new UserFriendlyException($"Video Call {((BusinessObjects.Employee)View.CurrentObject).Skype}")); 14 | NewAction(nameof(BusinessObjects.Employee.Email), "icon-email-16", 15 | _ => throw new UserFriendlyException("Click the editor value")); 16 | } 17 | 18 | private void NewAction(string id,string image,Action executed){ 19 | var simpleAction = new SimpleAction(this, id, id); 20 | simpleAction.ImageName = image; 21 | simpleAction.PaintStyle = ActionItemPaintStyle.Image; 22 | simpleAction.Executed += (_, _) => executed(simpleAction); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Employees/MailMergeController.cs: -------------------------------------------------------------------------------- 1 | using Aqua.EnumerableExtensions; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Actions; 4 | using DevExpress.ExpressApp.Office; 5 | using OutlookInspired.Module.BusinessObjects; 6 | using static OutlookInspired.Module.DatabaseUpdate.Updater; 7 | 8 | 9 | namespace OutlookInspired.Module.Features.Employees{ 10 | public class MailMergeController:ObjectViewController{ 11 | private RichTextShowInDocumentControllerBase _textShowInDocumentController; 12 | 13 | protected override void OnDeactivated(){ 14 | base.OnDeactivated(); 15 | if (_textShowInDocumentController==null)return; 16 | _textShowInDocumentController.ShowInDocumentAction.ItemsChanged-=ShowInDocumentActionOnItemsChanged; 17 | } 18 | 19 | protected override void OnActivated(){ 20 | base.OnActivated(); 21 | _textShowInDocumentController = Frame.GetController(); 22 | if (_textShowInDocumentController==null)return; 23 | _textShowInDocumentController.ShowInDocumentAction.ItemsChanged+=ShowInDocumentActionOnItemsChanged; 24 | } 25 | 26 | private void ShowInDocumentActionOnItemsChanged(object sender, ItemsChangedEventArgs e){ 27 | if (e.ChangedItemsInfo.All(pair => pair.Value == ChoiceActionItemChangesType.ItemsAdd)){ 28 | ((SingleChoiceAction)sender).Items.ForEach(item => item.ImageName = ((MailMergeDataInfo)item.Data).DisplayName 29 | switch{ 30 | MonthAward => "EmployeeQuickAward", 31 | ProbationNotice => "EmployeeQuickProbationNotice", 32 | ServiceExcellence => "EmployeeQuickExellece", 33 | ThankYouNote => "ThankYouNote", 34 | WelcomeToDevAV => "EmployeeQuickWelcome", 35 | _ => item.ImageName 36 | }); 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Employees/MapEmployeeController.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Actions; 4 | using DevExpress.ExpressApp.Model; 5 | using DevExpress.ExpressApp.Templates; 6 | using DevExpress.Persistent.Base; 7 | using OutlookInspired.Module.BusinessObjects; 8 | 9 | namespace OutlookInspired.Module.Features.Employees{ 10 | class MapEmployeeController:ObjectViewController{ 11 | public const string MapItActionId = "MapEmployee"; 12 | public MapEmployeeController(){ 13 | MapEmployeeAction = new PopupWindowShowAction(this, MapItActionId, PredefinedCategory.View){ 14 | ImageName = "MapIt", PaintStyle = ActionItemPaintStyle.Image,SelectionDependencyType = SelectionDependencyType.RequireSingleObject 15 | }; 16 | MapEmployeeAction.CustomizePopupWindowParams+=MapEmployeeActionOnCustomizePopupWindowParams; 17 | } 18 | 19 | private void MapEmployeeActionOnCustomizePopupWindowParams(object sender, CustomizePopupWindowParamsEventArgs e){ 20 | var objectSpace = Application.CreateObjectSpace(typeof(Employee)); 21 | var createdView = Application.CreateDetailView(objectSpace, 22 | (IModelDetailView)Application.Model.Views[Employee.MapsDetailView], false, objectSpace.GetObject(View.CurrentObject)); 23 | e.View=createdView; 24 | e.Size=new Size(1024,768); 25 | } 26 | 27 | public PopupWindowShowAction MapEmployeeAction{ get; } 28 | 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Maps/MapApiKeyProvider.cs: -------------------------------------------------------------------------------- 1 | namespace OutlookInspired.Module.Features.Maps{ 2 | public class MapApiKeyProvider : IMapApiKeyProvider { 3 | public string Key => Environment.GetEnvironmentVariable("BingKey"); 4 | } 5 | 6 | public interface IMapApiKeyProvider { 7 | public string Key{ get; } 8 | } 9 | 10 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Maps/Markers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.Persistent.Base; 4 | using OutlookInspired.Module.BusinessObjects; 5 | 6 | namespace OutlookInspired.Module.Features.Maps{ 7 | public interface IRouteMapsMarker:IMapsMarker{ 8 | 9 | } 10 | 11 | public interface ISalesMapsMarker:IMapsMarker,IObjectSpaceLink{ 12 | ObservableCollection Sales{ get; set; } 13 | ObservableCollection CitySales{ get; set; } 14 | IEnumerable Orders{ get; } 15 | 16 | } 17 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Orders/MapOrderController.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Actions; 4 | using DevExpress.ExpressApp.Model; 5 | using DevExpress.ExpressApp.Templates; 6 | using DevExpress.Persistent.Base; 7 | using OutlookInspired.Module.BusinessObjects; 8 | 9 | namespace OutlookInspired.Module.Features.Orders{ 10 | class MapOrderController:ObjectViewController{ 11 | public const string MapItActionId = "MapOrder"; 12 | public MapOrderController(){ 13 | MapOrderAction = new PopupWindowShowAction(this, MapItActionId, PredefinedCategory.View){ 14 | ImageName = "MapIt", PaintStyle = ActionItemPaintStyle.Image,SelectionDependencyType = SelectionDependencyType.RequireSingleObject 15 | }; 16 | MapOrderAction.CustomizePopupWindowParams+=MapOrderActionOnCustomizePopupWindowParams; 17 | } 18 | 19 | private void MapOrderActionOnCustomizePopupWindowParams(object sender, CustomizePopupWindowParamsEventArgs e){ 20 | var objectSpace = Application.CreateObjectSpace(typeof(Order)); 21 | var createdView = Application.CreateDetailView(objectSpace, 22 | (IModelDetailView)Application.Model.Views[Order.MapsDetailView], false, objectSpace.GetObject(View.CurrentObject)); 23 | e.View=createdView; 24 | e.Size=new Size(1024,768); 25 | } 26 | 27 | public PopupWindowShowAction MapOrderAction{ get; } 28 | 29 | } 30 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Orders/PayController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Data.Filtering; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Actions; 4 | using DevExpress.ExpressApp.Templates; 5 | using DevExpress.Persistent.Base; 6 | using OutlookInspired.Module.BusinessObjects; 7 | 8 | namespace OutlookInspired.Module.Features.Orders{ 9 | public class PayController:ObjectViewController{ 10 | public PayController(){ 11 | TargetObjectType = typeof(Order); 12 | var payOrderAction = new SimpleAction(this, "PayOrder", PredefinedCategory.Edit){ 13 | ImageName = "Payment", SelectionDependencyType = SelectionDependencyType.RequireSingleObject,PaintStyle = ActionItemPaintStyle.Image, 14 | TargetObjectsCriteria = CriteriaOperator.FromLambda(order => order.PaymentStatus==PaymentStatus.Unpaid).ToString(), 15 | ToolTip = "Mark as paid" 16 | }; 17 | payOrderAction.Executed+=EditInvoiceActionOnExecuted; 18 | } 19 | 20 | private void EditInvoiceActionOnExecuted(object sender, ActionBaseEventArgs e){ 21 | var order = ((Order)View.CurrentObject); 22 | order.PaymentTotal = order.TotalAmount; 23 | ObjectSpace.CommitChanges(); 24 | } 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Orders/RefundController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.Data.Filtering; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Actions; 4 | using DevExpress.ExpressApp.Templates; 5 | using DevExpress.Persistent.Base; 6 | using OutlookInspired.Module.BusinessObjects; 7 | 8 | namespace OutlookInspired.Module.Features.Orders{ 9 | public class RefundController:ObjectViewController{ 10 | public RefundController(){ 11 | TargetObjectType = typeof(Order); 12 | var refundAction = new SimpleAction(this, "RefundOrder", PredefinedCategory.Edit){ 13 | ImageName = "Refund", SelectionDependencyType = SelectionDependencyType.RequireSingleObject,PaintStyle = ActionItemPaintStyle.Image, 14 | TargetObjectsCriteria = CriteriaOperator.FromLambda(order => order.PaymentStatus==PaymentStatus.PaidInFull).ToString(), 15 | ToolTip = "Issue full refund" 16 | }; 17 | refundAction.Executed+=EditInvoiceActionOnExecuted; 18 | } 19 | 20 | private void EditInvoiceActionOnExecuted(object sender, ActionBaseEventArgs e){ 21 | var order = ((Order)View.CurrentObject); 22 | order.RefundTotal = order.PaymentTotal; 23 | ObjectSpace.CommitChanges(); 24 | } 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Products/MapProductController.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Actions; 4 | using DevExpress.ExpressApp.Model; 5 | using DevExpress.ExpressApp.Templates; 6 | using DevExpress.Persistent.Base; 7 | using OutlookInspired.Module.BusinessObjects; 8 | 9 | namespace OutlookInspired.Module.Features.Products{ 10 | class MapProductController:ObjectViewController{ 11 | public const string MapItActionId = "MapProduct"; 12 | public MapProductController(){ 13 | MapProductAction = new PopupWindowShowAction(this, MapItActionId, PredefinedCategory.View){ 14 | ImageName = "MapIt", PaintStyle = ActionItemPaintStyle.Image,SelectionDependencyType = SelectionDependencyType.RequireSingleObject 15 | }; 16 | MapProductAction.CustomizePopupWindowParams+=MapProductActionOnCustomizePopupWindowParams; 17 | } 18 | 19 | private void MapProductActionOnCustomizePopupWindowParams(object sender, CustomizePopupWindowParamsEventArgs e){ 20 | var objectSpace = Application.CreateObjectSpace(typeof(Product)); 21 | var createdView = Application.CreateDetailView(objectSpace, 22 | (IModelDetailView)Application.Model.Views[Product.MapsDetailView], false, objectSpace.GetObject(View.CurrentObject)); 23 | e.View=createdView; 24 | e.Size=new Size(1024,768); 25 | } 26 | 27 | public PopupWindowShowAction MapProductAction{ get; } 28 | 29 | } 30 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Quotes/MapOpportunitiesController.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Actions; 4 | using DevExpress.ExpressApp.Templates; 5 | using DevExpress.Persistent.Base; 6 | using OutlookInspired.Module.BusinessObjects; 7 | 8 | namespace OutlookInspired.Module.Features.Quotes{ 9 | public class MapOpportunitiesController:ObjectViewController{ 10 | public const string MapItActionId = "MapOpportunity"; 11 | public MapOpportunitiesController(){ 12 | MapOpportunitiesAction = new PopupWindowShowAction(this, MapItActionId, PredefinedCategory.View){ 13 | ImageName = "MapIt", PaintStyle = ActionItemPaintStyle.Image 14 | }; 15 | MapOpportunitiesAction.CustomizePopupWindowParams+=MapOpportunitiesActionOnCustomizePopupWindowParams; 16 | } 17 | 18 | private void MapOpportunitiesActionOnCustomizePopupWindowParams(object sender, CustomizePopupWindowParamsEventArgs e){ 19 | var objectSpace = Application.CreateObjectSpace(typeof(QuoteMapItem)); 20 | var createdView = Application.CreateListView(objectSpace, typeof(QuoteMapItem),false); 21 | e.View=createdView; 22 | e.Size=new Size(1024,768); 23 | } 24 | 25 | public PopupWindowShowAction MapOpportunitiesAction{ get; } 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Quotes/OpportunitiesFilterListViewController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Editors; 3 | using OutlookInspired.Module.BusinessObjects; 4 | 5 | namespace OutlookInspired.Module.Features.Quotes{ 6 | public class OpportunitiesFilterListViewController:ObjectViewController{ 7 | private CollectionSourceBase _quoteAnalysisCollectionSource; 8 | 9 | protected override void OnActivated(){ 10 | base.OnActivated(); 11 | var viewItem = ((NestedFrame)Frame).ViewItem; 12 | var item = ((DashboardView)viewItem.View).Items.Cast().First(dashboardViewItem =>dashboardViewItem.InnerView!=View ); 13 | _quoteAnalysisCollectionSource = ((ListView)item.InnerView).CollectionSource; 14 | _quoteAnalysisCollectionSource.CriteriaApplied+=QuoteAnalysisCollectionSourceOnCriteriaApplied; 15 | } 16 | 17 | protected override void OnDeactivated(){ 18 | base.OnDeactivated(); 19 | if (_quoteAnalysisCollectionSource==null)return; 20 | _quoteAnalysisCollectionSource.CriteriaApplied-=QuoteAnalysisCollectionSourceOnCriteriaApplied; 21 | } 22 | 23 | private void QuoteAnalysisCollectionSourceOnCriteriaApplied(object sender, EventArgs e){ 24 | View.CollectionSource.Criteria[nameof(OpportunitiesFilterListViewController)] = 25 | _quoteAnalysisCollectionSource.Criteria[nameof(ViewFilterController)]; 26 | ObjectSpace.Refresh(); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Features/Reports/ProtectReportActionItemsViewController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Actions; 3 | using DevExpress.ExpressApp.Security; 4 | using DevExpress.Persistent.BaseImpl.EF; 5 | 6 | namespace OutlookInspired.Module.Features.Reports{ 7 | public interface IReportController{ 8 | SingleChoiceAction ReportAction{ get; } 9 | } 10 | 11 | 12 | public class ProtectReportActionItemsViewController:ViewController{ 13 | protected override void OnViewControllersActivated(){ 14 | base.OnViewControllersActivated(); 15 | foreach (var singleChoiceAction in Frame.Controllers.Values.OfType().Select(controller => controller.ReportAction) 16 | .Where(action => action.Active)){ 17 | var items = SelectManyRecursive(singleChoiceAction.Items,item => item.Items); 18 | foreach (var item in items.Where(item => item.Data!=null)){ 19 | var reportDataV2 = ObjectSpace.GetObjectsQuery().FirstOrDefault(v2 => v2.DisplayName==(string)item.Data); 20 | if (reportDataV2==null) continue; 21 | var isGranted = ((IRequestSecurity)Application.Security).IsGranted(new PermissionRequest(ObjectSpace, 22 | reportDataV2.GetType(), SecurityOperations.Read, reportDataV2)); 23 | item.Active["ReportProtection"] = isGranted; 24 | } 25 | } 26 | } 27 | 28 | IEnumerable SelectManyRecursive( IEnumerable source, Func> childrenSelector){ 29 | foreach (var i in source){ 30 | yield return i; 31 | var children = childrenSelector(i); 32 | if (children == null) continue; 33 | foreach (var child in SelectManyRecursive(children, childrenSelector)) 34 | yield return child; 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/AllTasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/AllTasks.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Automation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/Automation.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Commission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/Commission.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Doctor.svg: -------------------------------------------------------------------------------- 1 | 3 | 6 | 9 | 11 | 12 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/EvaluationNo.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/EvaluationYes.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 9 | 10 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/High.svg: -------------------------------------------------------------------------------- 1 | 3 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/HighPriority.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/HighPriority.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Low.svg: -------------------------------------------------------------------------------- 1 | 3 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/LowPriority.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/LowPriority.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Medium.svg: -------------------------------------------------------------------------------- 1 | 3 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/MediumPriority.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/MediumPriority.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Miss.svg: -------------------------------------------------------------------------------- 1 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Monitors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/Monitors.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Mr.svg: -------------------------------------------------------------------------------- 1 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Mrs.svg: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Ms.svg: -------------------------------------------------------------------------------- 1 | 3 | 6 | 9 | 10 | 11 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/NormalPriority.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/NormalPriority.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/OnLeave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/OnLeave.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/PriorityHigh.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/PriorityLow.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/PriorityNormal.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/PriorityUrgent.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Probation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/Probation.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Projectors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/Projectors.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Salaried.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/Salaried.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Summary.svg: -------------------------------------------------------------------------------- 1 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/TVs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/TVs.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Terminated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/Terminated.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Unlike.svg: -------------------------------------------------------------------------------- 1 | 3 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/Urgent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/Urgent.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/VideoPlayers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/VideoPlayers.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/icon-email-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/icon-email-16.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/icon-home-phone-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/icon-home-phone-16.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Images/icon-mobile-phone-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Images/icon-mobile-phone-16.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/ModelInterfaces.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using DevExpress.ExpressApp.Model; 3 | using DevExpress.Persistent.Base; 4 | using OutlookInspired.Module.BusinessObjects; 5 | 6 | namespace OutlookInspired.Module{ 7 | public interface IModelOptionsHomeOffice{ 8 | IModelHomeOffice HomeOffice{ get; } 9 | } 10 | 11 | public interface IModelHomeOffice:IMapsMarker,IModelNode{ 12 | [DefaultValue("Glendale")] 13 | string City{ get; set; } 14 | [DefaultValue("91203")] 15 | string ZipCode{ get; set; } 16 | [DefaultValue("505 N. Brand Blvd")] 17 | string Line{ get; set; } 18 | [DefaultValue(StateEnum.CA)] 19 | StateEnum State{ get; set; } 20 | [DefaultValue(34.1532866)] 21 | new double Latitude{ get; set; } 22 | [DefaultValue(-118.2555815)] 23 | new double Longitude{ get; set; } 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/ModelUpdaters/DashboardViewsModelUpdater.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Model; 2 | using DevExpress.ExpressApp.Model.Core; 3 | using DevExpress.ExpressApp.Model.NodeGenerators; 4 | 5 | namespace OutlookInspired.Module.ModelUpdaters{ 6 | public class DashboardViewsModelUpdater : ModelNodesGeneratorUpdater{ 7 | 8 | public const string Opportunities = "Opportunities"; 9 | 10 | public override void UpdateNode(ModelNode node) => ((IModelViews)node).AddNode(Opportunities); 11 | } 12 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/ModelUpdaters/DataAccessModeUpdater.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Model; 3 | using DevExpress.ExpressApp.Model.Core; 4 | using DevExpress.ExpressApp.Model.NodeGenerators; 5 | using OutlookInspired.Module.BusinessObjects; 6 | 7 | namespace OutlookInspired.Module.ModelUpdaters{ 8 | 9 | public class DataAccessModeUpdater : ModelNodesGeneratorUpdater{ 10 | public static readonly Type[] ClientTypes =[typeof(Evaluation),typeof(TaskAttachedFile)]; 11 | 12 | public override void UpdateNode(ModelNode node){ 13 | var modelListViews = ((IModelViews)node).OfType() 14 | .Where(view => !ClientTypes.Contains(view.ModelClass.TypeInfo.Type)); 15 | foreach (var modelListView in modelListViews){ 16 | modelListView.DataAccessMode = modelListView.ModelClass.TypeInfo.IsPersistent 17 | ? CollectionSourceDataAccessMode.Server 18 | : CollectionSourceDataAccessMode.Client; 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Project Description 2 | 3 | This project implements a platform-agnostic Module. UI-independent application 4 | elements can be implemented here (Business Objects, Controllers, etc.). The root project 5 | folder contains the Module.cs(vb) file with the class that inherits ModuleBase. 6 | This class allows you to view and customize Module components: 7 | referenced modules, Controllers and business classes. Additionally, the root folder 8 | contains Application Model difference files (XAFML files) that keep application 9 | settings specific for the current Module. Difference files can be customized in code 10 | or in the Model Editor. 11 | 12 | 13 | Relevant Documentation 14 | 15 | Application Solution Components 16 | https://docs.devexpress.com/eXpressAppFramework/112569 17 | 18 | XAF Community Extensions 19 | https://www.devexpress.com/products/net/application_framework/#extensions 20 | 21 | Debugging, Unit and Functional Testing 22 | https://docs.devexpress.com/eXpressAppFramework/112572 23 | 24 | ModuleBase Class 25 | https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.ModuleBase 26 | 27 | 28 | Application Model 29 | https://docs.devexpress.com/eXpressAppFramework/112579 30 | 31 | Model Editor 32 | https://docs.devexpress.com/eXpressAppFramework/112582 -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Resources/MailMerge/FollowUp.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Resources/MailMerge/FollowUp.docx -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Resources/MailMerge/Month Award.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Resources/MailMerge/Month Award.docx -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Resources/MailMerge/Order.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Resources/MailMerge/Order.docx -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Resources/MailMerge/OrderItem.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Resources/MailMerge/OrderItem.docx -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Resources/MailMerge/Probation Notice.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Resources/MailMerge/Probation Notice.docx -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Resources/MailMerge/Service Excellence.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Resources/MailMerge/Service Excellence.docx -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Resources/MailMerge/Thank You Note.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Resources/MailMerge/Thank You Note.docx -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Resources/MailMerge/Welcome to DevAV.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Resources/MailMerge/Welcome to DevAV.docx -------------------------------------------------------------------------------- /CS/OutlookInspired.Module/Resources/Welcome.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Module/Resources/Welcome.pdf -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | System 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Controllers/DisableSkinsController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Win.SystemModule; 3 | 4 | namespace OutlookInspired.Win.Controllers{ 5 | public class DisableSkinsController:WindowController{ 6 | protected override void OnActivated(){ 7 | base.OnActivated(); 8 | Frame.GetController().Active[nameof(DisableSkinsController)]=false; 9 | } 10 | 11 | } 12 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Editors/ColumnViewUserControl.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace OutlookInspired.Win.Editors 2 | { 3 | partial class ColumnViewUserControl 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | protected override void Dispose(bool disposing) 11 | { 12 | if (disposing && (components != null)) 13 | { 14 | components.Dispose(); 15 | } 16 | base.Dispose(disposing); 17 | } 18 | 19 | 20 | #region Component Designer generated code 21 | 22 | /// 23 | /// Required method for Designer support - do not modify 24 | /// the contents of this method with the code editor. 25 | /// 26 | private void InitializeComponent() 27 | { 28 | SuspendLayout(); 29 | // 30 | // ColumnViewUserControl 31 | // 32 | AutoScaleDimensions = new SizeF(10F, 25F); 33 | AutoScaleMode = AutoScaleMode.Font; 34 | Name = "ColumnViewUserControl"; 35 | Size = new Size(1059, 839); 36 | ResumeLayout(false); 37 | } 38 | 39 | #endregion 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Editors/ColumnViewUserControl.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.XtraGrid; 2 | using DevExpress.XtraGrid.Views.Base; 3 | using OutlookInspired.Win.Editors.GridListEditor; 4 | 5 | 6 | namespace OutlookInspired.Win.Editors{ 7 | 8 | 9 | public partial class ColumnViewUserControl : UserControl, IColumnViewUserControl{ 10 | public ColumnView ColumnView=>(ColumnView)Controls.OfType().FirstOrDefault()?.MainView; 11 | public ColumnViewUserControl() => Load += OnLoad; 12 | 13 | private void OnLoad(object sender, EventArgs e) { 14 | if (ColumnView == null) return; 15 | ColumnView.ColumnFilterChanged += (_, _) => OnDataSourceOrFilterChanged(); 16 | ColumnView.DataSourceChanged += (_, _) => OnDataSourceOrFilterChanged(); 17 | ColumnView.DataError+=(_, args) => throw new AggregateException(args.DataException.Message,args.DataException); 18 | OnDataSourceOrFilterChanged(); 19 | } 20 | 21 | protected virtual void OnDataSourceOrFilterChanged(){ 22 | 23 | } 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Editors/EnumPropertyEditor.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Editors; 2 | using DevExpress.ExpressApp.Model; 3 | using DevExpress.ExpressApp.Win.Editors; 4 | using DevExpress.Utils; 5 | using DevExpress.XtraEditors.Repository; 6 | using EditorAliases = OutlookInspired.Module.EditorAliases; 7 | 8 | namespace OutlookInspired.Win.Editors{ 9 | [PropertyEditor(typeof(Enum),EditorAliases.EnumImageOnlyEditor,false)] 10 | public class EnumPropertyEditor(Type objectType, IModelMemberViewItem model) 11 | : DevExpress.ExpressApp.Win.Editors.EnumPropertyEditor(objectType, model){ 12 | protected override void SetupRepositoryItem(RepositoryItem item){ 13 | base.SetupRepositoryItem(item); 14 | ((RepositoryItemEnumEdit)item).GlyphAlignment=HorzAlignment.Center; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Editors/GridListEditor/FontSizeController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.SystemModule; 2 | using DevExpress.XtraGrid.Views.BandedGrid; 3 | using OutlookInspired.Module.Attributes; 4 | 5 | namespace OutlookInspired.Win.Editors.GridListEditor{ 6 | public class FontSizeController:ListViewControllerBase{ 7 | protected override void OnViewControlsCreated(){ 8 | base.OnViewControlsCreated(); 9 | if (View.Editor is not DevExpress.ExpressApp.Win.Editors.GridListEditor gridListEditor) return; 10 | if (gridListEditor.GridView is not AdvBandedGridView gridView) return; 11 | IncreaseFontSize(gridView); 12 | } 13 | 14 | void IncreaseFontSize(AdvBandedGridView gridView){ 15 | var attributedMembers = View.ObjectTypeInfo.Members.SelectMany(memberInfo => memberInfo.FindAttributes() 16 | .Select(attribute => (attribute, memberInfo))); 17 | var columns = attributedMembers 18 | .ToDictionary(attribute => gridView.Columns[attribute.memberInfo.BindingName].VisibleIndex, attribute => attribute.attribute.Delta); 19 | gridView.CustomDrawCell += (_, e) => { 20 | if (!columns.TryGetValue(e.Column.VisibleIndex, out var fontSizeDelta)) return; 21 | e.Appearance.FillRectangle(e.Cache, e.Bounds); 22 | e.Appearance.FontSizeDelta = fontSizeDelta; 23 | e.Appearance.DrawString(e.Cache, e.DisplayText, e.Bounds); 24 | e.Handled = true; 25 | }; 26 | } 27 | 28 | 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Editors/GridListEditor/NewItemRowHandlingModeController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Win.Editors; 3 | using ViewFilter = OutlookInspired.Module.BusinessObjects.ViewFilter; 4 | 5 | namespace OutlookInspired.Win.Editors.GridListEditor{ 6 | public class NewItemRowHandlingModeController:ObjectViewController{ 7 | protected override void OnViewControlsCreated(){ 8 | base.OnViewControlsCreated(); 9 | if (View.Editor is not DevExpress.ExpressApp.Win.Editors.GridListEditor listEditor) return; 10 | listEditor.NewItemRowHandlingMode=GridListEditorNewItemRowHandlingMode.NativeControl; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Editors/LabelControlPropertyEditor.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Editors; 2 | using DevExpress.ExpressApp.Model; 3 | using DevExpress.ExpressApp.Win.Editors; 4 | using DevExpress.Utils; 5 | using DevExpress.XtraEditors; 6 | using DevExpress.XtraEditors.Controls; 7 | using DevExpress.XtraRichEdit; 8 | using OutlookInspired.Module.Attributes; 9 | using EditorAliases = OutlookInspired.Module.EditorAliases; 10 | 11 | namespace OutlookInspired.Win.Editors{ 12 | [PropertyEditor(typeof(object),EditorAliases.LabelPropertyEditor,false)] 13 | public class LabelControlPropertyEditor : WinPropertyEditor{ 14 | private static readonly RichEditDocumentServer RichEditDocumentServer = new(); 15 | public LabelControlPropertyEditor(Type objectType, IModelMemberViewItem model) : base(objectType, model) 16 | => ControlBindingProperty = "Text"; 17 | 18 | public override bool CanFormatPropertyValue => true; 19 | 20 | protected override object CreateControlCore() 21 | => new LabelControl{ 22 | BorderStyle = BorderStyles.NoBorder, 23 | AutoSizeMode = LabelAutoSizeMode.None, 24 | ShowLineShadow = false, 25 | Appearance ={ 26 | FontSizeDelta = MemberInfo.FindAttribute()?.Delta??0, 27 | TextOptions = { WordWrap = (MemberInfo.Size == -1||MemberInfo.MemberType==typeof(byte[]))? WordWrap.Wrap:WordWrap.Default} 28 | } 29 | }; 30 | 31 | protected override void ReadValueCore(){ 32 | if (PropertyValue is byte[] bytes){ 33 | RichEditDocumentServer.LoadDocument(bytes,DocumentFormat.OpenXml); 34 | Control.Text = RichEditDocumentServer.Text; 35 | } 36 | else{ 37 | Control.Text = $"{PropertyValue}"; 38 | } 39 | 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Editors/PdfViewerEditor.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using DevExpress.ExpressApp.Editors; 3 | using DevExpress.ExpressApp.Model; 4 | using DevExpress.ExpressApp.Win.Editors; 5 | using DevExpress.XtraPdfViewer; 6 | using EditorAliases = OutlookInspired.Module.EditorAliases; 7 | 8 | namespace OutlookInspired.Win.Editors{ 9 | [PropertyEditor(typeof(byte[]), EditorAliases.PdfViewerEditor, false)] 10 | public class PdfViewerEditor(Type objectType, IModelMemberViewItem info) : WinPropertyEditor(objectType, info){ 11 | public new PdfViewer Control => (PdfViewer)base.Control; 12 | protected override object CreateControlCore() 13 | => new PdfViewer{ 14 | Dock = DockStyle.Fill, DetachStreamAfterLoadComplete = true, ZoomMode = PdfZoomMode.PageLevel, 15 | NavigationPaneVisibility = PdfNavigationPaneVisibility.Hidden, 16 | NavigationPaneInitialVisibility = PdfNavigationPaneVisibility.Hidden 17 | }; 18 | 19 | protected override void ReadValueCore(){ 20 | if (PropertyValue is not byte[]{ Length: > 0 } bytes) return; 21 | using var memoryStream = new MemoryStream(bytes); 22 | Control?.LoadDocument(memoryStream); 23 | 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Editors/PrintLayoutRichTextEditor.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.Editors; 2 | using DevExpress.ExpressApp.Model; 3 | using DevExpress.XtraRichEdit; 4 | using EditorAliases = OutlookInspired.Module.EditorAliases; 5 | using RichTextPropertyEditor = DevExpress.ExpressApp.Office.Win.RichTextPropertyEditor; 6 | 7 | namespace OutlookInspired.Win.Editors{ 8 | [PropertyEditor(typeof(byte[]), EditorAliases.PrintLayoutRichTextEditor, false)] 9 | public class PrintLayoutRichTextEditor(Type objectType, IModelMemberViewItem info) 10 | : RichTextPropertyEditor(objectType, info){ 11 | protected override object CreateControlCore(){ 12 | var controlCore = base.CreateControlCore(); 13 | RichEditControl.ActiveViewType=RichEditViewType.PrintLayout; 14 | return controlCore; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/ExpressApp.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Win/ExpressApp.ico -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Customers/CustomerColumnViewListEditorController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using OutlookInspired.Module.BusinessObjects; 3 | using OutlookInspired.Win.Editors.GridListEditor; 4 | 5 | namespace OutlookInspired.Win.Features.Customers{ 6 | public class CustomerColumnViewListEditorController:ObjectViewController{ 7 | protected override void OnActivated(){ 8 | base.OnActivated(); 9 | if (View.Editor is not ColumnViewListEditor listEditor) return; 10 | listEditor.ColumnViewControlCreating+=ListEditorOnColumnViewControlCreating; 11 | } 12 | 13 | protected override void OnDeactivated(){ 14 | base.OnDeactivated(); 15 | if (View.Editor is not ColumnViewListEditor listEditor) return; 16 | listEditor.ColumnViewControlCreating-=ListEditorOnColumnViewControlCreating; 17 | } 18 | 19 | private void ListEditorOnColumnViewControlCreating(object sender, ColumnViewControlCreatingArgs e) 20 | => e.Control =View.Id== Customer.LayoutViewListView?new CustomerLayoutView():new CustomerGridView(); 21 | } 22 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Customers/CustomerGridView.cs: -------------------------------------------------------------------------------- 1 | using OutlookInspired.Win.Editors; 2 | 3 | namespace OutlookInspired.Win.Features.Customers 4 | { 5 | public partial class CustomerGridView : ColumnViewUserControl 6 | { 7 | public CustomerGridView() 8 | { 9 | InitializeComponent(); 10 | } 11 | 12 | 13 | } 14 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Customers/CustomerLayoutView.cs: -------------------------------------------------------------------------------- 1 | using OutlookInspired.Win.Editors; 2 | 3 | namespace OutlookInspired.Win.Features.Customers 4 | { 5 | public partial class CustomerLayoutView : ColumnViewUserControl 6 | { 7 | public CustomerLayoutView() 8 | { 9 | InitializeComponent(); 10 | labelControl1.Text = @"RECORDS: 0"; 11 | } 12 | 13 | protected override void OnDataSourceOrFilterChanged(){ 14 | base.OnDataSourceOrFilterChanged(); 15 | labelControl1.Text = $@"RECORDS: {ColumnView.DataRowCount}"; 16 | } 17 | 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Customers/CustomerStoreColumnViewListEditorController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using OutlookInspired.Module.BusinessObjects; 3 | using OutlookInspired.Win.Editors.GridListEditor; 4 | 5 | namespace OutlookInspired.Win.Features.Customers{ 6 | public class CustomerStoreColumnViewListEditorController:ObjectViewController{ 7 | protected override void OnActivated(){ 8 | base.OnActivated(); 9 | if (View.Editor is not ColumnViewListEditor listEditor) return; 10 | listEditor.ColumnViewControlCreating+=ListEditorOnColumnViewControlCreating; 11 | } 12 | 13 | protected override void OnDeactivated(){ 14 | base.OnDeactivated(); 15 | if (View.Editor is not ColumnViewListEditor listEditor) return; 16 | listEditor.ColumnViewControlCreating-=ListEditorOnColumnViewControlCreating; 17 | } 18 | 19 | private void ListEditorOnColumnViewControlCreating(object sender, ColumnViewControlCreatingArgs e) 20 | => e.Control =new CustomerStoreView(); 21 | } 22 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Customers/CustomerStoreView.cs: -------------------------------------------------------------------------------- 1 | using OutlookInspired.Win.Editors; 2 | 3 | namespace OutlookInspired.Win.Features.Customers 4 | { 5 | 6 | public partial class CustomerStoreView : ColumnViewUserControl 7 | { 8 | public CustomerStoreView() 9 | { 10 | InitializeComponent(); 11 | labelControl1.Text = $@"RECORDS: 0"; 12 | } 13 | protected override void OnDataSourceOrFilterChanged(){ 14 | base.OnDataSourceOrFilterChanged(); 15 | labelControl1.Text = $@"RECORDS: {ColumnView.DataRowCount}"; 16 | } 17 | 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Employees/EmployeeColumnViewListEditorController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using OutlookInspired.Module.BusinessObjects; 3 | using OutlookInspired.Win.Editors.GridListEditor; 4 | 5 | namespace OutlookInspired.Win.Features.Employees{ 6 | public class EmployeeColumnViewListEditorController:ObjectViewController{ 7 | protected override void OnActivated(){ 8 | base.OnActivated(); 9 | if (View.Editor is not ColumnViewListEditor listEditor) return; 10 | listEditor.ColumnViewControlCreating+=ListEditorOnColumnViewControlCreating; 11 | } 12 | 13 | protected override void OnDeactivated(){ 14 | base.OnDeactivated(); 15 | if (View.Editor is not ColumnViewListEditor listEditor) return; 16 | listEditor.ColumnViewControlCreating-=ListEditorOnColumnViewControlCreating; 17 | } 18 | 19 | private void ListEditorOnColumnViewControlCreating(object sender, ColumnViewControlCreatingArgs e) => e.Control = new EmployeesLayoutView(); 20 | } 21 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Employees/EmployeesLayoutView.cs: -------------------------------------------------------------------------------- 1 | using OutlookInspired.Win.Editors; 2 | 3 | namespace OutlookInspired.Win.Features.Employees 4 | { 5 | public partial class EmployeesLayoutView : ColumnViewUserControl{ 6 | public EmployeesLayoutView(){ 7 | InitializeComponent(); 8 | labelControl1.Text = @"RECORDS: 0"; 9 | } 10 | 11 | protected override void OnDataSourceOrFilterChanged(){ 12 | base.OnDataSourceOrFilterChanged(); 13 | labelControl1.Text = $@"RECORDS: {ColumnView.DataRowCount}"; 14 | } 15 | 16 | 17 | } 18 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Employees/MapsTravelModeViewController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Actions; 3 | using DevExpress.ExpressApp.Templates; 4 | using DevExpress.Persistent.Base; 5 | using DevExpress.XtraMap; 6 | using OutlookInspired.Module.BusinessObjects; 7 | using OutlookInspired.Win.Editors.Maps; 8 | 9 | namespace OutlookInspired.Win.Features.Employees{ 10 | public class MapsTravelModeViewController:ObjectViewController{ 11 | private readonly SingleChoiceAction _action; 12 | 13 | public MapsTravelModeViewController(){ 14 | TargetViewId = Employee.MapsDetailView; 15 | _action = new SingleChoiceAction(this,"TravelMode",PredefinedCategory.PopupActions); 16 | _action.Items.AddRange([new ChoiceActionItem("Driving", BingTravelMode.Driving){ ImageName = "Driving" }, 17 | new ChoiceActionItem("Walking", BingTravelMode.Walking){ ImageName = "Walking" } 18 | ]); 19 | _action.SelectedItem = _action.Items.First(); 20 | _action.ItemType=SingleChoiceActionItemType.ItemIsOperation; 21 | _action.ImageMode=ImageMode.UseItemImage; 22 | _action.DefaultItemMode = DefaultItemMode.LastExecutedItem; 23 | _action.PaintStyle=ActionItemPaintStyle.Image; 24 | _action.Executed+=ActionOnExecuted; 25 | } 26 | 27 | 28 | private void ActionOnExecuted(object sender, ActionBaseEventArgs e){ 29 | var editor = View.GetItems().First(); 30 | editor.CalculateRoute((BingTravelMode)_action.SelectedItem.Data); 31 | } 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Evaluations/SchedulerListEditorController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Scheduler.Win; 3 | using DevExpress.XtraScheduler; 4 | using OutlookInspired.Module.BusinessObjects; 5 | 6 | namespace OutlookInspired.Win.Features.Evaluations{ 7 | public class SchedulerListEditorController:ObjectViewController{ 8 | protected override void OnViewControlsCreated(){ 9 | base.OnViewControlsCreated(); 10 | if (View.Editor is not SchedulerListEditor editor)return; 11 | editor.SchedulerControl.GroupType = SchedulerGroupType.None; 12 | editor.ResourcesMappings.Id = nameof(Employee.ID); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Maps/Colorizer.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.XtraCharts; 2 | 3 | namespace OutlookInspired.Win.Features.Maps{ 4 | public class Colorizer : DevExpress.XtraMap.KeyColorColorizer, IColorizer { 5 | 6 | event System.ComponentModel.PropertyChangedEventHandler System.ComponentModel.INotifyPropertyChanged.PropertyChanged { 7 | add { } 8 | remove { } 9 | } 10 | 11 | public Color GetPointColor(object argument, object[] values, object colorKey, Palette palette) 12 | => colorKey != null ? GetColor(colorKey) : Color.Empty; 13 | 14 | public Color GetPointColor(object argument, object[] values, object[] colorKeys, Palette palette) 15 | => colorKeys is{ Length: > 0 } ? GetColor(colorKeys[0]) : Color.Empty; 16 | 17 | public Color GetAggregatedPointColor(object argument, object[] values, SeriesPoint[] points, Palette palette) 18 | => Color.Empty; 19 | } 20 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Orders/OrderColumnViewListEditorController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using OutlookInspired.Module.BusinessObjects; 3 | using OutlookInspired.Win.Editors.GridListEditor; 4 | 5 | namespace OutlookInspired.Win.Features.Orders{ 6 | public class OrderColumnViewListEditorController:ObjectViewController{ 7 | protected override void OnActivated(){ 8 | base.OnActivated(); 9 | if (View.Editor is not ColumnViewListEditor listEditor) return; 10 | listEditor.ColumnViewControlCreating+=ListEditorOnColumnViewControlCreating; 11 | } 12 | 13 | protected override void OnDeactivated(){ 14 | base.OnDeactivated(); 15 | if (View.Editor is not ColumnViewListEditor listEditor) return; 16 | listEditor.ColumnViewControlCreating-=ListEditorOnColumnViewControlCreating; 17 | } 18 | 19 | private void ListEditorOnColumnViewControlCreating(object sender, ColumnViewControlCreatingArgs e) 20 | => e.Control =new OrderDetailView(); 21 | } 22 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Orders/OrderDetailView.cs: -------------------------------------------------------------------------------- 1 | using OutlookInspired.Win.Editors; 2 | 3 | namespace OutlookInspired.Win.Features.Orders 4 | { 5 | public partial class OrderDetailView : ColumnViewUserControl 6 | { 7 | public OrderDetailView() 8 | { 9 | InitializeComponent(); 10 | labelControl1.Text = @"RECORDS: 0"; 11 | } 12 | 13 | protected override void OnDataSourceOrFilterChanged() 14 | { 15 | base.OnDataSourceOrFilterChanged(); 16 | labelControl1.Text = $@"RECORDS: {ColumnView.DataRowCount}"; 17 | } 18 | 19 | 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Orders/OrderGridView.cs: -------------------------------------------------------------------------------- 1 | using OutlookInspired.Win.Editors; 2 | 3 | namespace OutlookInspired.Win.Features.Orders 4 | { 5 | public partial class OrderGridView : ColumnViewUserControl 6 | { 7 | public OrderGridView() 8 | { 9 | InitializeComponent(); 10 | } 11 | 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Products/ProductCardView.cs: -------------------------------------------------------------------------------- 1 | using OutlookInspired.Win.Editors; 2 | 3 | namespace OutlookInspired.Win.Features.Products 4 | { 5 | public partial class ProductCardView : ColumnViewUserControl 6 | { 7 | public ProductCardView() 8 | { 9 | InitializeComponent(); 10 | labelControl1.Text = @"RECORDS: 0"; 11 | } 12 | 13 | protected override void OnDataSourceOrFilterChanged() 14 | { 15 | base.OnDataSourceOrFilterChanged(); 16 | labelControl1.Text = $@"RECORDS: {ColumnView.DataRowCount}"; 17 | } 18 | 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Products/ProductColumnViewListEditorController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using OutlookInspired.Module.BusinessObjects; 3 | using OutlookInspired.Win.Editors.GridListEditor; 4 | 5 | namespace OutlookInspired.Win.Features.Products{ 6 | public class ProductColumnViewListEditorController:ObjectViewController{ 7 | protected override void OnActivated(){ 8 | base.OnActivated(); 9 | if (View.Editor is not ColumnViewListEditor listEditor) return; 10 | listEditor.ColumnViewControlCreating+=ListEditorOnColumnViewControlCreating; 11 | } 12 | 13 | protected override void OnDeactivated(){ 14 | base.OnDeactivated(); 15 | if (View.Editor is not ColumnViewListEditor listEditor) return; 16 | listEditor.ColumnViewControlCreating-=ListEditorOnColumnViewControlCreating; 17 | } 18 | 19 | private void ListEditorOnColumnViewControlCreating(object sender, ColumnViewControlCreatingArgs e) 20 | => e.Control =new ProductCardView(); 21 | } 22 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Quotes/QuoteAnalysisPivotGridListEditorController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.PivotGrid.Win; 3 | using OutlookInspired.Module.BusinessObjects; 4 | 5 | namespace OutlookInspired.Win.Features.Quotes{ 6 | public class WinQuoteAnalysisPivotGridListEditorController:ObjectViewController{ 7 | protected override void OnActivated(){ 8 | base.OnActivated(); 9 | View.CollectionSource.CriteriaApplied+=CollectionSourceOnCriteriaApplied; 10 | } 11 | 12 | protected override void OnDeactivated(){ 13 | base.OnDeactivated(); 14 | View.CollectionSource.CriteriaApplied-=CollectionSourceOnCriteriaApplied; 15 | } 16 | 17 | private void CollectionSourceOnCriteriaApplied(object sender, EventArgs e){ 18 | ObjectSpace.Refresh(); 19 | ((PivotGridListEditor)View.Editor).ChartControl.RefreshData(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Features/Quotes/WinOpportunitiesChartListViewController.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp; 2 | using DevExpress.ExpressApp.Chart.Win; 3 | using DevExpress.XtraCharts; 4 | using OutlookInspired.Module.BusinessObjects; 5 | 6 | namespace OutlookInspired.Win.Features.Quotes{ 7 | public class WinOpportunitiesChartListViewController:ObjectViewController{ 8 | protected override void OnActivated(){ 9 | base.OnActivated(); 10 | Active[$"not {nameof(ChartListEditor)}"] = View.Editor is ChartListEditor; 11 | } 12 | 13 | protected override void OnViewControlsCreated(){ 14 | base.OnViewControlsCreated(); 15 | ((ChartControl)View.Editor.Control).CustomDrawSeriesPoint+=OnCustomDrawSeriesPoint; 16 | } 17 | 18 | private void OnCustomDrawSeriesPoint(object sender, CustomDrawSeriesPointEventArgs e){ 19 | if (e.SeriesPoint.Tag is not Opportunity opportunity) return; 20 | e.SeriesDrawOptions.Color = ColorTranslator.FromHtml(opportunity.Stage.Color()); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Images/ExpressAppLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/CS/OutlookInspired.Win/Images/ExpressAppLogo.png -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Images/Logo.svg: -------------------------------------------------------------------------------- 1 | 3 | 6 | 16 | 17 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Images/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Folder Description 2 | 3 | The "Images" project folder is intended for storing custom image files. 4 | 5 | 6 | Relevant Documentation 7 | 8 | Add and Override Images 9 | https://docs.devexpress.com/eXpressAppFramework/112792 10 | 11 | Assign a Custom Image 12 | https://docs.devexpress.com/eXpressAppFramework/112744 13 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Initialization.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Diagnostics; 4 | using DevExpress.Persistent.Base; 5 | 6 | namespace OutlookInspired.Win; 7 | 8 | public class Initialization { 9 | public static void KillServerProcess() { 10 | Process existProc = Process.GetProcessesByName("OutlookInspired.MiddleTier").FirstOrDefault(); 11 | if (existProc != null) { 12 | existProc.Kill(); 13 | existProc.WaitForExit(); 14 | } 15 | } 16 | public static Process RunSecurityServer(IEnumerable args) { 17 | KillServerProcess(); 18 | var proc = new Process(); 19 | proc.StartInfo.WindowStyle = ProcessWindowStyle.Minimized; 20 | if (args.Any()) { 21 | proc.StartInfo.Arguments = string.Concat(proc.StartInfo.Arguments, " ", string.Join(" ", args.Select(a => "\"" + a + "\""))); 22 | } 23 | string buildConfiguration = Path.GetFileName(Path.GetDirectoryName(Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, @"..\")))); 24 | string middleTierDirectory = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, @$"..\..\..\..\OutlookInspired.MiddleTier"); 25 | string workingDirectory = Path.Combine(middleTierDirectory, @$"Bin\{buildConfiguration}\net8.0"); 26 | string fileName = Path.Combine(workingDirectory, "OutlookInspired.MiddleTier.exe"); 27 | if (!File.Exists(fileName)) { 28 | throw new FileNotFoundException("Could not start a server process. The OutlookInspired.MiddleTier.exe file is missing.\r\nPlease ensure that you have built the OutlookInspired.MiddleTier project."); 29 | } 30 | proc.StartInfo.FileName = fileName; 31 | proc.StartInfo.WorkingDirectory = middleTierDirectory; 32 | proc.Start(); 33 | return proc; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Configuration; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using DevExpress.ExpressApp; 5 | using DevExpress.Persistent.Base; 6 | using DevExpress.XtraEditors; 7 | 8 | namespace OutlookInspired.Win; 9 | 10 | static class Program { 11 | [STAThread] 12 | public static int Main(string[] args){ 13 | 14 | FrameworkSettings.DefaultSettingsCompatibilityMode = FrameworkSettingsCompatibilityMode.Latest; 15 | #if EASYTEST 16 | DevExpress.ExpressApp.Win.EasyTest.EasyTestRemotingRegistration.Register(); 17 | #endif 18 | WindowsFormsSettings.LoadApplicationSettings(); 19 | Application.EnableVisualStyles(); 20 | Application.SetCompatibleTextRenderingDefault(false); 21 | DevExpress.Utils.ToolTipController.DefaultController.ToolTipType = DevExpress.Utils.ToolTipType.SuperTip; 22 | if(Tracing.GetFileLocationFromSettings() == FileLocation.CurrentUserApplicationDataFolder) { 23 | Tracing.LocalUserAppDataPath = Application.LocalUserAppDataPath; 24 | } 25 | Tracing.Initialize(); 26 | Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development"); 27 | 28 | Initialization.RunSecurityServer(args); 29 | 30 | var winApplication = ApplicationBuilder.BuildApplication(); 31 | try { 32 | 33 | winApplication.Setup(); 34 | winApplication.Start(); 35 | } 36 | catch(Exception e) { 37 | winApplication.StopSplash(); 38 | winApplication.HandleException(e); 39 | } 40 | return 0; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Project Description 2 | 3 | This project implements a WinForms application. The root project folder 4 | contains the WinApplication.cs file with the class that inherits WinApplication. 5 | This class allows you to view and customize Module components: 6 | referenced modules, Controllers and business classes. Additionally, the root folder 7 | contains Application Model difference files (XAFML files) that keep application 8 | settings specific for the current Module. Difference files can be customized in code 9 | or in the Model Editor. 10 | 11 | 12 | Relevant Documentation 13 | 14 | Application Solution Components 15 | https://docs.devexpress.com/eXpressAppFramework/112569 16 | 17 | XAF Community Extensions 18 | https://www.devexpress.com/products/net/application_framework/#extensions 19 | 20 | Debugging, Unit and Functional Testing 21 | https://docs.devexpress.com/eXpressAppFramework/112572 22 | 23 | WinApplication Class 24 | https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Win.WinApplication 25 | 26 | XafApplication Class 27 | https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.XafApplication 28 | 29 | Application Model 30 | https://docs.devexpress.com/eXpressAppFramework/112579 31 | 32 | Model Editor 33 | https://docs.devexpress.com/eXpressAppFramework/112582 -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/WinApplication.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.ExpressApp.SystemModule; 2 | using DevExpress.ExpressApp.Win; 3 | 4 | namespace OutlookInspired.Win; 5 | public class OutlookInspiredWindowsFormsApplication : WinApplication{ 6 | public OutlookInspiredWindowsFormsApplication(){ 7 | AboutInfo.Instance.Version = "Version " + AssemblyInfo.FileVersion; 8 | AboutInfo.Instance.Copyright = AssemblyInfo.AssemblyCopyright + " All Rights Reserved"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/WinModule.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using DevExpress.ExpressApp; 3 | using DevExpress.ExpressApp.Editors; 4 | using DevExpress.ExpressApp.Updating; 5 | using DevExpress.Persistent.BaseImpl.EF; 6 | using OutlookInspired.Module; 7 | 8 | namespace OutlookInspired.Win; 9 | 10 | [ToolboxItemFilter("Xaf.Platform.Win")] 11 | public sealed class OutlookInspiredWinModule : ModuleBase { 12 | private void Application_CreateCustomUserModelDifferenceStore(object sender, CreateCustomModelDifferenceStoreEventArgs e) { 13 | e.Store = new ModelDifferenceDbStore((XafApplication)sender, typeof(ModelDifference), false, "Win"); 14 | e.Handled = true; 15 | } 16 | public OutlookInspiredWinModule() { 17 | FormattingProvider.UseMaskSettings = true; 18 | RequiredModuleTypes.Add(typeof(OutlookInspiredModule)); 19 | } 20 | public override IEnumerable GetModuleUpdaters(IObjectSpace objectSpace, Version versionFromDB) 21 | =>[new(objectSpace, versionFromDB)]; 22 | 23 | 24 | public override void Setup(XafApplication application) { 25 | base.Setup(application); 26 | application.CreateCustomUserModelDifferenceStore += Application_CreateCustomUserModelDifferenceStore; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/XafDemoSplashScreen.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using DevExpress.ExpressApp.Win.Utils; 3 | using DevExpress.Utils.Svg; 4 | using DevExpress.XtraSplashScreen; 5 | 6 | namespace OutlookInspired.Win { 7 | public partial class XafDemoSplashScreen : DemoSplashScreen { 8 | private string GetSplashScreenImageResourcesName() { 9 | string splashScreenImageResourceName = "SplashScreenImage.svg"; 10 | foreach(string resourceName in Assembly.GetExecutingAssembly().GetManifestResourceNames()) { 11 | if(resourceName.EndsWith(splashScreenImageResourceName)) { 12 | return resourceName; 13 | } 14 | } 15 | return splashScreenImageResourceName; 16 | } 17 | private void LoadSplashImageFromResource() { 18 | var assembly = Assembly.GetExecutingAssembly(); 19 | var svgStream = assembly.GetManifestResourceStream(GetSplashScreenImageResourcesName()); 20 | if (svgStream is null) { 21 | throw new System.IO.FileNotFoundException(GetSplashScreenImageResourcesName()); 22 | } 23 | svgStream.Position = 0; 24 | pictureEdit2.SvgImage = SvgImage.FromStream(svgStream); 25 | } 26 | public XafDemoSplashScreen() { 27 | InitializeComponent(); 28 | LoadSplashImageFromResource(); 29 | Load += (_, _) => BackColor = Color.FromArgb(46,46,46); 30 | } 31 | public override void ProcessCommand(Enum cmd, object arg) { 32 | base.ProcessCommand(cmd, arg); 33 | if((UpdateSplashCommand)cmd == UpdateSplashCommand.Description) { 34 | labelControl2.Text = (string)arg; 35 | } 36 | } 37 | protected override void DrawBackground(PaintEventArgs e){ } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Components.Web -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/wwwroot/css/app.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 3 | } 4 | 5 | h1:focus { 6 | outline: none; 7 | } 8 | 9 | a, .btn-link { 10 | color: #0071c1; 11 | } 12 | 13 | .btn-primary { 14 | color: #fff; 15 | background-color: #1b6ec2; 16 | border-color: #1861ac; 17 | } 18 | 19 | .valid.modified:not([type=checkbox]) { 20 | outline: 1px solid #26b050; 21 | } 22 | 23 | .invalid { 24 | outline: 1px solid red; 25 | } 26 | 27 | .validation-message { 28 | color: red; 29 | } 30 | 31 | #blazor-error-ui { 32 | background: lightyellow; 33 | bottom: 0; 34 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); 35 | display: none; 36 | left: 0; 37 | padding: 0.6rem 1.25rem 0.7rem 1.25rem; 38 | position: fixed; 39 | width: 100%; 40 | z-index: 1000; 41 | } 42 | 43 | #blazor-error-ui .dismiss { 44 | cursor: pointer; 45 | position: absolute; 46 | right: 0.75rem; 47 | top: 0.5rem; 48 | } -------------------------------------------------------------------------------- /CS/OutlookInspired.Win/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WinFormsBlazor 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
Loading...
15 | 16 |
17 | An unhandled error has occurred. 18 | Reload 19 | 🗙 20 |
21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Data/OutlookInspired.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Data/OutlookInspired.zip -------------------------------------------------------------------------------- /Images/AzureBuild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/AzureBuild.png -------------------------------------------------------------------------------- /Images/BOImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/BOImage.png -------------------------------------------------------------------------------- /Images/BlazorChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/BlazorChart.png -------------------------------------------------------------------------------- /Images/BlazorFontDelta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/BlazorFontDelta.png -------------------------------------------------------------------------------- /Images/BlazorTravelDistance.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/BlazorTravelDistance.jpg -------------------------------------------------------------------------------- /Images/CardViews.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/CardViews.png -------------------------------------------------------------------------------- /Images/CustomerReportAction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/CustomerReportAction.png -------------------------------------------------------------------------------- /Images/DomainModel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/DomainModel.png -------------------------------------------------------------------------------- /Images/EmployeeCard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/EmployeeCard.png -------------------------------------------------------------------------------- /Images/EmployeeWinLayout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/EmployeeWinLayout.png -------------------------------------------------------------------------------- /Images/EnumPropertyEditorWin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/EnumPropertyEditorWin.png -------------------------------------------------------------------------------- /Images/FollowUp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/FollowUp.png -------------------------------------------------------------------------------- /Images/HostUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/HostUI.png -------------------------------------------------------------------------------- /Images/HyperLinkEditorWin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/HyperLinkEditorWin.png -------------------------------------------------------------------------------- /Images/HyperLinkLabel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/HyperLinkLabel.png -------------------------------------------------------------------------------- /Images/LabelWinEditor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/LabelWinEditor.png -------------------------------------------------------------------------------- /Images/ManageTenants.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/ManageTenants.png -------------------------------------------------------------------------------- /Images/Opportunities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/Opportunities.png -------------------------------------------------------------------------------- /Images/OpportunitiesListView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/OpportunitiesListView.png -------------------------------------------------------------------------------- /Images/OpportunitiesMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/OpportunitiesMap.png -------------------------------------------------------------------------------- /Images/OrderDetailView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/OrderDetailView.png -------------------------------------------------------------------------------- /Images/OrderInvoice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/OrderInvoice.png -------------------------------------------------------------------------------- /Images/PdfViewerBlazor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/PdfViewerBlazor.png -------------------------------------------------------------------------------- /Images/PdfViewerWin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/PdfViewerWin.png -------------------------------------------------------------------------------- /Images/ProductCardView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/ProductCardView.png -------------------------------------------------------------------------------- /Images/ProductReports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/ProductReports.png -------------------------------------------------------------------------------- /Images/ProgressEditorWin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/ProgressEditorWin.png -------------------------------------------------------------------------------- /Images/RevenueAnalysis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/RevenueAnalysis.png -------------------------------------------------------------------------------- /Images/Scheduler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/Scheduler.png -------------------------------------------------------------------------------- /Images/ShowInDocumentIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/ShowInDocumentIcon.png -------------------------------------------------------------------------------- /Images/Solution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/Solution.png -------------------------------------------------------------------------------- /Images/StoresView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/StoresView.png -------------------------------------------------------------------------------- /Images/TasksView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/TasksView.png -------------------------------------------------------------------------------- /Images/TenantUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/TenantUI.png -------------------------------------------------------------------------------- /Images/TestsFolders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/TestsFolders.png -------------------------------------------------------------------------------- /Images/ViewFilterAction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/ViewFilterAction.png -------------------------------------------------------------------------------- /Images/ViewFilterView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/ViewFilterView.png -------------------------------------------------------------------------------- /Images/WatermarkReport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/WatermarkReport.png -------------------------------------------------------------------------------- /Images/WinFontDelta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/WinFontDelta.png -------------------------------------------------------------------------------- /Images/WinMasterDetailGrid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/WinMasterDetailGrid.png -------------------------------------------------------------------------------- /Images/WinOppurtunityMaps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/WinOppurtunityMaps.png -------------------------------------------------------------------------------- /Images/WinProductLayout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/WinProductLayout.png -------------------------------------------------------------------------------- /Images/WinSalesMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/WinSalesMap.png -------------------------------------------------------------------------------- /Images/WinTravelDistance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/WinTravelDistance.png -------------------------------------------------------------------------------- /Images/XafImg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/xaf-create-multitenant-application/abdf13fc386299fc03fb1c6a0183adfcf1361ffc/Images/XafImg.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This code example is provided "as is" without warranty of any kind. Developer Express Inc ("DevExpress") disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. 2 | 3 | For licensing terms and conditions of DevExpress product(s) required for, or associated with the use of this code example, please refer to the applicable End-User License Agreement at https://www.devexpress.com/Support/licensingfaq.xml -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | This code example is provided "as is" without warranty of any kind. Developer Express Inc ("DevExpress") disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. 2 | 3 | For licensing terms and conditions of DevExpress product(s) required for, or associated with the use of this code example, please refer to the applicable End-User License Agreement at https://www.devexpress.com/Support/licensingfaq.xml -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: ImportData 3 | displayName: 'ImportData Job' 4 | dependsOn: [] 5 | timeoutInMinutes: 90 6 | variables: 7 | defaultWorkingDir: '$(System.DefaultWorkingDirectory)\CS' 8 | runSettingsPath: '$(defaultWorkingDir)\Tests\Tests.runsettings' 9 | testsFolderPath: '$(defaultWorkingDir)\Tests' 10 | dxFeedVar: '$(DXFeed)' 11 | NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages 12 | pool: 13 | name: Self 14 | steps: 15 | - task: PowerShell@2 16 | displayName: Build 17 | continueOnError: false 18 | inputs: 19 | targetType: 'inline' 20 | script: | 21 | & sqllocaldb start mssqllocaldb 22 | dotnet nuget add source $(dxFeedVar) --name DX 23 | cd "$(defaultWorkingDir)" 24 | dotnet build --configuration TEST 25 | Get-ChildItem -Path "$(testsFolderPath)" -Recurse -Directory -Include "ref", "refint", "obj" | ForEach-Object { Remove-Item $_.FullName -Recurse -Force } 26 | pwsh: true 27 | - task: VSTest@3 28 | displayName: 'ImportData.Test' 29 | continueOnError: false 30 | enabled: true 31 | inputs: 32 | minimumExpectedTests: "1" 33 | failOnMinTestsNotRun: true 34 | searchFolder: $(testsFolderPath) 35 | testSelector: 'testAssemblies' 36 | testAssemblyVer2: '**\OutlookInspired.Win.Tests.dll' 37 | testFiltercriteria: TestCategory=ImportData 38 | diagnosticsEnabled: true 39 | codeCoverageEnabled: true 40 | runSettingsFile: $(runSettingsPath) 41 | 42 | - template: job-template.yml 43 | parameters: 44 | testAssembly: '**\OutlookInspired.Win.Tests.dll' 45 | displayName: 'Windows' 46 | 47 | - template: job-template.yml 48 | parameters: 49 | testAssembly: '**\OutlookInspired.Blazor.Tests.dll' 50 | displayName: 'Blazor' 51 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "runOnWeb": false, 3 | "autoGenerateVb": false 4 | } 5 | -------------------------------------------------------------------------------- /job-template.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | testAssembly: '' 3 | displayName: '' 4 | jobs: 5 | - job: ${{ parameters.displayName }} 6 | variables: 7 | defaultWorkingDir: '$(System.DefaultWorkingDirectory)\CS' 8 | runSettingsPath: '$(defaultWorkingDir)\Tests\Tests.runsettings' 9 | testsFolderPath: '$(defaultWorkingDir)\Tests' 10 | dxFeedVar: '$(DXFeed)' 11 | NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages 12 | strategy: 13 | matrix: 14 | Admin: {} 15 | Sales: {} 16 | Support: {} 17 | Management: {} 18 | Engineering: {} 19 | IT: {} 20 | Shipping: {} 21 | HumanResources: {} 22 | timeoutInMinutes: 90 23 | pool: 24 | name: Self 25 | steps: 26 | - task: PowerShell@2 27 | displayName: Build 28 | continueOnError: false 29 | inputs: 30 | targetType: 'inline' 31 | script: | 32 | Write-Output "${{ parameters.testAssembly }}" 33 | & sqllocaldb start mssqllocaldb 34 | dotnet nuget add source $(dxFeedVar) --name DX 35 | cd "$(defaultWorkingDir)" 36 | dotnet build --configuration TEST 37 | Get-ChildItem -Path "$(testsFolderPath)" -Recurse -Directory -Include "ref", "refint", "obj" | 38 | ForEach-Object { Remove-Item $_.FullName -Recurse -Force } 39 | pwsh: true 40 | - task: VSTest@3 41 | displayName: ${{ parameters.displayName }} 42 | continueOnError: false 43 | env: 44 | TEST_ROLE: $(Agent.JobName) 45 | BingKey: $(BingKey) 46 | enabled: true 47 | inputs: 48 | minimumExpectedTests: "1" 49 | failOnMinTestsNotRun: true 50 | rerunFailedTests: false 51 | searchFolder: $(testsFolderPath) 52 | testSelector: 'testAssemblies' 53 | testAssemblyVer2: ${{ parameters.testAssembly }} 54 | testFiltercriteria: TestCategory=Tests 55 | diagnosticsEnabled: true 56 | codeCoverageEnabled: true 57 | uiTests: true 58 | runSettingsFile: $(runSettingsPath) 59 | 60 | --------------------------------------------------------------------------------