diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..a88e69e --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @DevExpressExampleBot \ No newline at end of file diff --git a/CustomParameterEditor.Client/CustomParameterEditor.client.esproj b/CustomParameterEditor.Client/CustomParameterEditor.client.esproj new file mode 100644 index 0000000..f4204bc --- /dev/null +++ b/CustomParameterEditor.Client/CustomParameterEditor.client.esproj @@ -0,0 +1,9 @@ + + + npm start + + false + + $(MSBuildProjectDirectory)\dist\CustomParameterEditor.client\browser\ + + diff --git a/CustomParameterEditor.Client/README.md b/CustomParameterEditor.Client/README.md new file mode 100644 index 0000000..c80f1d9 --- /dev/null +++ b/CustomParameterEditor.Client/README.md @@ -0,0 +1,59 @@ +# CustomParameterEditor.client + +This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.1.3. + +## Development server + +To start a local development server, run: + +```bash +ng serve +``` + +Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files. + +## Code scaffolding + +Angular CLI includes powerful code scaffolding tools. To generate a new component, run: + +```bash +ng generate component component-name +``` + +For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: + +```bash +ng generate --help +``` + +## Building + +To build the project run: + +```bash +ng build +``` + +This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed. + +## Running unit tests + +To execute unit tests with the [Vitest](https://vitest.dev/) test runner, use the following command: + +```bash +ng test +``` + +## Running end-to-end tests + +For end-to-end (e2e) testing, run: + +```bash +ng e2e +``` + +Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. + +## Additional Resources + +For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. diff --git a/CustomParameterEditor.Client/angular.json b/CustomParameterEditor.Client/angular.json new file mode 100644 index 0000000..d332263 --- /dev/null +++ b/CustomParameterEditor.Client/angular.json @@ -0,0 +1,82 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "cli": { + "packageManager": "npm" + }, + "newProjectRoot": "projects", + "projects": { + "CustomParameterEditor.client": { + "projectType": "application", + "schematics": {}, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "browser": "src/main.ts", + "tsConfig": "tsconfig.app.json", + "assets": [ + { + "glob": "**/*", + "input": "public" + } + ], + "styles": [ + "node_modules/bootstrap/dist/css/bootstrap.min.css", + "src/styles.css" + ], + "server": "src/main.server.ts", + "outputMode": "server", + "ssr": { + "entry": "src/server.ts" + } + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "1000kB", + "maximumError": "30MB" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "100kB", + "maximumError": "1MB" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular/build:dev-server", + "configurations": { + "production": { + "buildTarget": "CustomParameterEditor.client:build:production" + }, + "development": { + "buildTarget": "CustomParameterEditor.client:build:development" + } + }, + "defaultConfiguration": "development", + "options": { + "proxyConfig": "src/proxy.conf.js" + } + }, + "test": { + "builder": "@angular/build:unit-test" + } + } + } + } +} diff --git a/CustomParameterEditor.Client/aspnetcore-https.js b/CustomParameterEditor.Client/aspnetcore-https.js new file mode 100644 index 0000000..5665e3f --- /dev/null +++ b/CustomParameterEditor.Client/aspnetcore-https.js @@ -0,0 +1,37 @@ +// This script sets up HTTPS for the application using the ASP.NET Core HTTPS certificate +const fs = require('fs'); +const spawn = require('child_process').spawn; +const path = require('path'); + +const baseFolder = + process.env.APPDATA !== undefined && process.env.APPDATA !== '' + ? `${process.env.APPDATA}/ASP.NET/https` + : `${process.env.HOME}/.aspnet/https`; + +const certificateArg = process.argv.map(arg => arg.match(/--name=(?.+)/i)).filter(Boolean)[0]; +const certificateName = certificateArg ? certificateArg.groups.value : process.env.npm_package_name; + +if (!certificateName) { + console.error('Invalid certificate name. Run this script in the context of an npm/yarn script or pass --name=<> explicitly.') + process.exit(-1); +} + +const certFilePath = path.join(baseFolder, `${certificateName}.pem`); +const keyFilePath = path.join(baseFolder, `${certificateName}.key`); + +if(!fs.existsSync(baseFolder)) { + fs.mkdirSync(baseFolder, { recursive: true }); +} + +if (!fs.existsSync(certFilePath) || !fs.existsSync(keyFilePath)) { + spawn('dotnet', [ + 'dev-certs', + 'https', + '--export-path', + certFilePath, + '--format', + 'Pem', + '--no-password', + ], { stdio: 'inherit', }) + .on('exit', (code) => process.exit(code)); +} \ No newline at end of file diff --git a/CustomParameterEditor.Client/package.json b/CustomParameterEditor.Client/package.json new file mode 100644 index 0000000..51195b4 --- /dev/null +++ b/CustomParameterEditor.Client/package.json @@ -0,0 +1,56 @@ +{ + "name": "CustomParameterEditor", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "run-script-os", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "prestart": "node aspnetcore-https", + "start:windows": "ng serve --ssl --ssl-cert \"%APPDATA%\\ASP.NET\\https\\%npm_package_name%.pem\" --ssl-key \"%APPDATA%\\ASP.NET\\https\\%npm_package_name%.key\"", + "start:default": "ng serve --ssl --ssl-cert \"$HOME/.aspnet/https/${npm_package_name}.pem\" --ssl-key \"$HOME/.aspnet/https/${npm_package_name}.key\"", + "test": "ng test" + }, + "prettier": { + "printWidth": 100, + "singleQuote": true, + "overrides": [ + { + "files": "*.html", + "options": { + "parser": "angular" + } + } + ] + }, + "private": true, + "packageManager": "npm@11.6.2", + "dependencies": { + "@angular/common": "^21.1.0", + "@angular/compiler": "^21.1.0", + "@angular/core": "^21.1.0", + "@angular/forms": "^21.1.0", + "@angular/platform-browser": "^21.1.0", + "@angular/platform-server": "^21.1.0", + "@angular/router": "^21.1.0", + "@angular/ssr": "^21.1.3", + "express": "^5.1.0", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "run-script-os": "^1.1.0", + "bootstrap": "^5.3.3", + "devexpress-reporting-angular": "25.2-stable", + "devextreme": "25.2-stable", + "devextreme-angular": "25.2-stable" + }, + "devDependencies": { + "@angular/build": "^21.1.3", + "@angular/cli": "^21.1.3", + "@angular/compiler-cli": "^21.1.0", + "@types/express": "^5.0.1", + "@types/node": "^20.17.19", + "jsdom": "^27.1.0", + "typescript": "~5.9.2", + "vitest": "^4.0.8" + } +} \ No newline at end of file diff --git a/CustomParameterEditor.Client/public/favicon.ico b/CustomParameterEditor.Client/public/favicon.ico new file mode 100644 index 0000000..57614f9 Binary files /dev/null and b/CustomParameterEditor.Client/public/favicon.ico differ diff --git a/CustomParameterEditor.Client/src/app/app.config.server.ts b/CustomParameterEditor.Client/src/app/app.config.server.ts new file mode 100644 index 0000000..41031f1 --- /dev/null +++ b/CustomParameterEditor.Client/src/app/app.config.server.ts @@ -0,0 +1,12 @@ +import { mergeApplicationConfig, ApplicationConfig } from '@angular/core'; +import { provideServerRendering, withRoutes } from '@angular/ssr'; +import { appConfig } from './app.config'; +import { serverRoutes } from './app.routes.server'; + +const serverConfig: ApplicationConfig = { + providers: [ + provideServerRendering(withRoutes(serverRoutes)) + ] +}; + +export const config = mergeApplicationConfig(appConfig, serverConfig); diff --git a/CustomParameterEditor.Client/src/app/app.config.ts b/CustomParameterEditor.Client/src/app/app.config.ts new file mode 100644 index 0000000..9c517bd --- /dev/null +++ b/CustomParameterEditor.Client/src/app/app.config.ts @@ -0,0 +1,20 @@ +import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core'; +import { provideRouter } from '@angular/router'; +import { routes } from './app.routes'; +import { provideClientHydration, withEventReplay } from '@angular/platform-browser'; +import { provideHttpClient, withFetch } from '@angular/common/http'; +import { TemplateEngine } from 'devexpress-reporting-angular/dx-report-viewer'; + +function getBaseUrl() { + return document.getElementsByTagName('base')[0].href; +} + +export const appConfig: ApplicationConfig = { + providers: [ + provideBrowserGlobalErrorListeners(), + provideRouter(routes), provideClientHydration(withEventReplay()), + provideHttpClient(withFetch()), + TemplateEngine, + { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] } + ] +}; diff --git a/CustomParameterEditor.Client/src/app/app.css b/CustomParameterEditor.Client/src/app/app.css new file mode 100644 index 0000000..e69de29 diff --git a/CustomParameterEditor.Client/src/app/app.html b/CustomParameterEditor.Client/src/app/app.html new file mode 100644 index 0000000..4a19fef --- /dev/null +++ b/CustomParameterEditor.Client/src/app/app.html @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/CustomParameterEditor.Client/src/app/app.routes.server.ts b/CustomParameterEditor.Client/src/app/app.routes.server.ts new file mode 100644 index 0000000..75dabc5 --- /dev/null +++ b/CustomParameterEditor.Client/src/app/app.routes.server.ts @@ -0,0 +1,7 @@ +import { RenderMode, ServerRoute } from '@angular/ssr'; + +export const serverRoutes: ServerRoute[] = [ + { path: 'DocumentViewer', renderMode: RenderMode.Client }, + { path: '', renderMode: RenderMode.Prerender }, + { path: '**', renderMode: RenderMode.Client } +]; \ No newline at end of file diff --git a/CustomParameterEditor.Client/src/app/app.routes.ts b/CustomParameterEditor.Client/src/app/app.routes.ts new file mode 100644 index 0000000..01f4308 --- /dev/null +++ b/CustomParameterEditor.Client/src/app/app.routes.ts @@ -0,0 +1,8 @@ +import { Routes } from '@angular/router'; +import { Home } from './home/home'; + +export const routes: Routes = [ + { path: '', component: Home, pathMatch: 'full' }, + { path: 'DocumentViewer', loadComponent: () => import('./reportviewer/report-viewer').then(m => m.ReportViewer) }, + { path: 'CustomInput', loadComponent: () => import('./custominputcomponent/custom-input-component').then(m => m.CustomInput) } +]; \ No newline at end of file diff --git a/CustomParameterEditor.Client/src/app/app.spec.ts b/CustomParameterEditor.Client/src/app/app.spec.ts new file mode 100644 index 0000000..8c88328 --- /dev/null +++ b/CustomParameterEditor.Client/src/app/app.spec.ts @@ -0,0 +1,19 @@ +import { TestBed } from '@angular/core/testing'; +import { provideRouter } from '@angular/router'; +import { App } from './app'; +import { routes } from './app.routes'; + +describe('App', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [App], + providers: [provideRouter(routes)] + }).compileComponents(); + }); + + it('should create the app', () => { + const fixture = TestBed.createComponent(App); + const app = fixture.componentInstance; + expect(app).toBeTruthy(); + }); +}); diff --git a/CustomParameterEditor.Client/src/app/app.ts b/CustomParameterEditor.Client/src/app/app.ts new file mode 100644 index 0000000..39dd575 --- /dev/null +++ b/CustomParameterEditor.Client/src/app/app.ts @@ -0,0 +1,15 @@ +import { Component, signal } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; +import { NavMenu } from './navmenu/nav-menu'; + +@Component({ + selector: 'app-root', + standalone: true, + imports: [RouterOutlet, NavMenu], + + templateUrl: './app.html', + styleUrl: './app.css' +}) +export class App { + protected readonly title = signal('CustomParameterEditor'); +} diff --git a/CustomParameterEditor.Client/src/app/custominputcomponent/custom-input-component.html b/CustomParameterEditor.Client/src/app/custominputcomponent/custom-input-component.html new file mode 100644 index 0000000..d4c31ad --- /dev/null +++ b/CustomParameterEditor.Client/src/app/custominputcomponent/custom-input-component.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/CustomParameterEditor.Client/src/app/custominputcomponent/custom-input-component.ts b/CustomParameterEditor.Client/src/app/custominputcomponent/custom-input-component.ts new file mode 100644 index 0000000..7caf546 --- /dev/null +++ b/CustomParameterEditor.Client/src/app/custominputcomponent/custom-input-component.ts @@ -0,0 +1,13 @@ +import { Component, Input } from '@angular/core'; +import { IEditorViewModel } from '@devexpress/analytics-core/analytics-widgets-native'; +import { DxTextBoxModule, DxValidatorModule } from 'devextreme-angular'; + +@Component({ + selector: 'custom-input-component', + templateUrl: 'custom-input-component.html', + standalone: true, + imports: [DxTextBoxModule, DxValidatorModule] +}) +export class CustomInput { + @Input('data') data!: IEditorViewModel; +} diff --git a/CustomParameterEditor.Client/src/app/home/home.html b/CustomParameterEditor.Client/src/app/home/home.html new file mode 100644 index 0000000..7d04e6f --- /dev/null +++ b/CustomParameterEditor.Client/src/app/home/home.html @@ -0,0 +1,23 @@ +
+

ASP.NET Core Reporting Application

+

Welcome to your new single-page application, built with:

+ +

Application uses

+
    +
  • Reporting Client-Side Widgets
  • +
  • ASP.NET Core MVC Reporting Controllers
  • +
+

Overview

+ +
\ No newline at end of file diff --git a/CustomParameterEditor.Client/src/app/home/home.ts b/CustomParameterEditor.Client/src/app/home/home.ts new file mode 100644 index 0000000..56cff8e --- /dev/null +++ b/CustomParameterEditor.Client/src/app/home/home.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-home', + templateUrl: './home.html', + standalone: true +}) +export class Home { + protected readonly links = [ + { url: 'https://docs.devexpress.com/XtraReports/2162/index', text: 'Reporting' }, + { url: 'https://docs.devexpress.com/XtraReports/9814/web-reporting', text: 'Web Reporting' }, + { url: 'https://docs.devexpress.com/XtraReports/401914/web-reporting/javascript-reporting/angular', text: 'Reporting for Angular' }, + { url: 'https://docs.devexpress.com/XtraReports/400292/web-reporting/javascript-reporting/angular/document-viewer/quick-start/document-viewer-client-side-configuration-angular', text: 'Web Document Viewer Client-Side Configuration' }, + { url: 'https://docs.devexpress.com/XtraReports/401726/web-reporting/general-information-on-web-reporting/troubleshooting', text: 'Troubleshooting' } + ] as const; +} diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/navmenu/nav-menu.component.css b/CustomParameterEditor.Client/src/app/navmenu/nav-menu.css similarity index 93% rename from CustomParameterEditorAngularExample/ClientApp/src/app/navmenu/nav-menu.component.css rename to CustomParameterEditor.Client/src/app/navmenu/nav-menu.css index 8592457..10389ef 100644 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/navmenu/nav-menu.component.css +++ b/CustomParameterEditor.Client/src/app/navmenu/nav-menu.css @@ -1,18 +1,18 @@ -a.navbar-brand { - white-space: normal; - text-align: center; - word-break: break-all; -} - -html { - font-size: 14px; -} -@media (min-width: 768px) { - html { - font-size: 16px; - } -} - -.box-shadow { - box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); -} +a.navbar-brand { + white-space: normal; + text-align: center; + word-break: break-all; +} + +html { + font-size: 14px; +} +@media (min-width: 768px) { + html { + font-size: 16px; + } +} + +.box-shadow { + box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); +} diff --git a/CustomParameterEditor.Client/src/app/navmenu/nav-menu.html b/CustomParameterEditor.Client/src/app/navmenu/nav-menu.html new file mode 100644 index 0000000..f574e03 --- /dev/null +++ b/CustomParameterEditor.Client/src/app/navmenu/nav-menu.html @@ -0,0 +1,26 @@ +
+ +
diff --git a/CustomParameterEditor.Client/src/app/navmenu/nav-menu.ts b/CustomParameterEditor.Client/src/app/navmenu/nav-menu.ts new file mode 100644 index 0000000..6cfac0b --- /dev/null +++ b/CustomParameterEditor.Client/src/app/navmenu/nav-menu.ts @@ -0,0 +1,21 @@ +import { Component, signal } from '@angular/core'; +import { RouterLink, RouterLinkActive } from '@angular/router'; + +@Component({ + selector: 'app-nav-menu', + templateUrl: './nav-menu.html', + styleUrls: ['./nav-menu.css'], + standalone: true, + imports: [RouterLink, RouterLinkActive] +}) +export class NavMenu { + protected readonly isExpanded = signal(false); + + collapse() { + this.isExpanded.set(false); + } + + toggle() { + this.isExpanded.update(value => !value); + } +} diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/reportviewer/report-viewer.html b/CustomParameterEditor.Client/src/app/reportviewer/report-viewer.html similarity index 69% rename from CustomParameterEditorAngularExample/ClientApp/src/app/reportviewer/report-viewer.html rename to CustomParameterEditor.Client/src/app/reportviewer/report-viewer.html index 26514cf..93abc4c 100644 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/reportviewer/report-viewer.html +++ b/CustomParameterEditor.Client/src/app/reportviewer/report-viewer.html @@ -1,5 +1,9 @@ - - - - + + + + + + + + \ No newline at end of file diff --git a/CustomParameterEditor.Client/src/app/reportviewer/report-viewer.ts b/CustomParameterEditor.Client/src/app/reportviewer/report-viewer.ts new file mode 100644 index 0000000..4a7677e --- /dev/null +++ b/CustomParameterEditor.Client/src/app/reportviewer/report-viewer.ts @@ -0,0 +1,41 @@ +import { AfterViewInit, Component, Inject, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; +import { DxReportDesignerModule, DxReportViewerModule } from 'devexpress-reporting-angular'; +import { TemplateEngine } from 'devexpress-reporting-angular/dx-report-viewer'; +import { CustomInput } from '../custominputcomponent/custom-input-component'; + +@Component({ + selector: 'report-viewer', + encapsulation: ViewEncapsulation.None, + templateUrl: './report-viewer.html', + styleUrls: [ + "../../../node_modules/devextreme/dist/css/dx.material.blue.light.css", + "../../../node_modules/@devexpress/analytics-core/dist/css/dx-analytics.common.css", + "../../../node_modules/@devexpress/analytics-core/dist/css/dx-analytics.material.blue.light.css", + "../../../node_modules/devexpress-reporting/dist/css/dx-webdocumentviewer.css" + ], + standalone: true, + imports: [DxReportViewerModule, DxReportDesignerModule, CustomInput] +}) +export class ReportViewer implements AfterViewInit { + protected readonly reportUrl: string = 'CustomParameterReport'; + protected readonly invokeAction: string = '/DXXRDV'; + + @ViewChild('myCustomInput') myCustomInput!: TemplateRef<{ data: any }>; + + ngAfterViewInit(): void { + this._templateEngine.register('custom-parameter-text-editor', this.myCustomInput); + } + + onCustomizeParameterEditors(event: any): void { + const parameter = event.args.parameter; + const info = event.args.info; + if (parameter.type === 'CustomParameterType') { + info.validationRules = info.validationRules || []; + info.validationRules.push( + { type: 'email', message: 'Email parameter value has invalid format.' }); + info.editor.header = "custom-parameter-text-editor"; + } + } + + constructor(@Inject('BASE_URL') protected readonly hostUrl: string, private _templateEngine: TemplateEngine) { } +} diff --git a/CustomParameterEditorAngularExample/ClientApp/src/index.html b/CustomParameterEditor.Client/src/index.html similarity index 74% rename from CustomParameterEditorAngularExample/ClientApp/src/index.html rename to CustomParameterEditor.Client/src/index.html index 68b9f00..f715095 100644 --- a/CustomParameterEditorAngularExample/ClientApp/src/index.html +++ b/CustomParameterEditor.Client/src/index.html @@ -1,14 +1,13 @@ - - - - - WebApplication1 - - - - - - - Loading... - - + + + + + CustomParameterEditor + + + + + + + + diff --git a/CustomParameterEditor.Client/src/main.server.ts b/CustomParameterEditor.Client/src/main.server.ts new file mode 100644 index 0000000..723e001 --- /dev/null +++ b/CustomParameterEditor.Client/src/main.server.ts @@ -0,0 +1,8 @@ +import { BootstrapContext, bootstrapApplication } from '@angular/platform-browser'; +import { App } from './app/app'; +import { config } from './app/app.config.server'; + +const bootstrap = (context: BootstrapContext) => + bootstrapApplication(App, config, context); + +export default bootstrap; diff --git a/CustomParameterEditor.Client/src/main.ts b/CustomParameterEditor.Client/src/main.ts new file mode 100644 index 0000000..5df75f9 --- /dev/null +++ b/CustomParameterEditor.Client/src/main.ts @@ -0,0 +1,6 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { App } from './app/app'; + +bootstrapApplication(App, appConfig) + .catch((err) => console.error(err)); diff --git a/CustomParameterEditor.Client/src/proxy.conf.js b/CustomParameterEditor.Client/src/proxy.conf.js new file mode 100644 index 0000000..58372ba --- /dev/null +++ b/CustomParameterEditor.Client/src/proxy.conf.js @@ -0,0 +1,16 @@ +const { env } = require('process'); + +const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}` : + env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'https://localhost:44332/'; + +const PROXY_CONFIG = [ + { + context: [ + "/DXXRD", "/DXXQB", "/DXXRDV" + ], + target, + secure: false + } +] + +module.exports = PROXY_CONFIG; diff --git a/CustomParameterEditor.Client/src/server.ts b/CustomParameterEditor.Client/src/server.ts new file mode 100644 index 0000000..4bf0631 --- /dev/null +++ b/CustomParameterEditor.Client/src/server.ts @@ -0,0 +1,68 @@ +import { + AngularNodeAppEngine, + createNodeRequestHandler, + isMainModule, + writeResponseToNodeResponse, +} from '@angular/ssr/node'; +import express from 'express'; +import { join } from 'node:path'; + +const browserDistFolder = join(import.meta.dirname, '../browser'); + +const app = express(); +const angularApp = new AngularNodeAppEngine(); + +/** + * Example Express Rest API endpoints can be defined here. + * Uncomment and define endpoints as necessary. + * + * Example: + * ```ts + * app.get('/api/{*splat}', (req, res) => { + * // Handle API request + * }); + * ``` + */ + +/** + * Serve static files from /browser + */ +app.use( + express.static(browserDistFolder, { + maxAge: '1y', + index: false, + redirect: false, + }), +); + +/** + * Handle all other requests by rendering the Angular application. + */ +app.use((req, res, next) => { + angularApp + .handle(req) + .then((response) => + response ? writeResponseToNodeResponse(response, res) : next(), + ) + .catch(next); +}); + +/** + * Start the server if this module is the main entry point, or it is ran via PM2. + * The server listens on the port defined by the `PORT` environment variable, or defaults to 4000. + */ +if (isMainModule(import.meta.url) || process.env['pm_id']) { + const port = process.env['PORT'] || 4000; + app.listen(port, (error) => { + if (error) { + throw error; + } + + console.log(`Node Express server listening on http://localhost:${port}`); + }); +} + +/** + * Request handler used by the Angular CLI (for dev-server and during build) or Firebase Cloud Functions. + */ +export const reqHandler = createNodeRequestHandler(app); diff --git a/CustomParameterEditorAngularExample/ClientApp/src/styles.css b/CustomParameterEditor.Client/src/styles.css similarity index 98% rename from CustomParameterEditorAngularExample/ClientApp/src/styles.css rename to CustomParameterEditor.Client/src/styles.css index 9907dc1..90d4ee0 100644 --- a/CustomParameterEditorAngularExample/ClientApp/src/styles.css +++ b/CustomParameterEditor.Client/src/styles.css @@ -1 +1 @@ -/* You can add global styles to this file, and also import other style files */ +/* You can add global styles to this file, and also import other style files */ diff --git a/CustomParameterEditor.Client/tsconfig.app.json b/CustomParameterEditor.Client/tsconfig.app.json new file mode 100644 index 0000000..ef19921 --- /dev/null +++ b/CustomParameterEditor.Client/tsconfig.app.json @@ -0,0 +1,17 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [ + "node" + ] + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/**/*.spec.ts" + ] +} diff --git a/CustomParameterEditor.Client/tsconfig.json b/CustomParameterEditor.Client/tsconfig.json new file mode 100644 index 0000000..2ab7442 --- /dev/null +++ b/CustomParameterEditor.Client/tsconfig.json @@ -0,0 +1,33 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "compileOnSave": false, + "compilerOptions": { + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "isolatedModules": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "ES2022", + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + }, + "files": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/CustomParameterEditor.Client/tsconfig.spec.json b/CustomParameterEditor.Client/tsconfig.spec.json new file mode 100644 index 0000000..d383706 --- /dev/null +++ b/CustomParameterEditor.Client/tsconfig.spec.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "vitest/globals" + ] + }, + "include": [ + "src/**/*.d.ts", + "src/**/*.spec.ts" + ] +} diff --git a/CustomParameterEditorAngularExample/Controllers/HomeController.cs b/CustomParameterEditor.Server/Controllers/HomeController.cs similarity index 85% rename from CustomParameterEditorAngularExample/Controllers/HomeController.cs rename to CustomParameterEditor.Server/Controllers/HomeController.cs index 6acdf75..deeb36d 100644 --- a/CustomParameterEditorAngularExample/Controllers/HomeController.cs +++ b/CustomParameterEditor.Server/Controllers/HomeController.cs @@ -1,19 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; - -namespace CustomParameterEditorAngularExample.Controllers { - public class HomeController : Controller { - public IActionResult Index() { - return View(); - } - - public IActionResult Error() { - ViewData["RequestId"] = Activity.Current?.Id ?? HttpContext.TraceIdentifier; - return View(); - } - } +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace CustomParameterEditor.Controllers { + public class HomeController : Controller { + public IActionResult Index() { + return View(); + } + + public IActionResult Error() { + ViewData["RequestId"] = Activity.Current?.Id ?? HttpContext.TraceIdentifier; + return View(); + } + } } \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/Controllers/ReportingControllers.cs b/CustomParameterEditor.Server/Controllers/ReportingControllers.cs similarity index 72% rename from CustomParameterEditorAngularExample/Controllers/ReportingControllers.cs rename to CustomParameterEditor.Server/Controllers/ReportingControllers.cs index b2eb06a..a85539b 100644 --- a/CustomParameterEditorAngularExample/Controllers/ReportingControllers.cs +++ b/CustomParameterEditor.Server/Controllers/ReportingControllers.cs @@ -1,10 +1,10 @@ -using DevExpress.AspNetCore.Reporting.WebDocumentViewer; -using DevExpress.AspNetCore.Reporting.WebDocumentViewer.Native.Services; -using Microsoft.AspNetCore.Mvc; - -namespace CustomParameterEditorAngularExample.Controllers { - public class CustomWebDocumentViewerController : WebDocumentViewerController { - public CustomWebDocumentViewerController(IWebDocumentViewerMvcControllerService controllerService) : base(controllerService) { - } - } -} \ No newline at end of file +using DevExpress.AspNetCore.Reporting.WebDocumentViewer; +using DevExpress.AspNetCore.Reporting.WebDocumentViewer.Native.Services; +using Microsoft.AspNetCore.Mvc; + +namespace CustomParameterEditor.Controllers { + public class CustomWebDocumentViewerController : WebDocumentViewerController { + public CustomWebDocumentViewerController(IWebDocumentViewerMvcControllerService controllerService) : base(controllerService) { + } + } +} diff --git a/CustomParameterEditor.Server/CustomParameterEditor.Server.csproj b/CustomParameterEditor.Server/CustomParameterEditor.Server.csproj new file mode 100644 index 0000000..92d7ae2 --- /dev/null +++ b/CustomParameterEditor.Server/CustomParameterEditor.Server.csproj @@ -0,0 +1,42 @@ + + + + net8.0 + enable + ..\CustomParameterEditor.Client + npm start + https://localhost:4200 + + + + + + + + + + + + + false + + + + + + + + + PreserveNewest + + + + + + + + + + + + \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/Data/ReportDbContext.cs b/CustomParameterEditor.Server/Data/ReportDbContext.cs similarity index 95% rename from CustomParameterEditorAngularExample/Data/ReportDbContext.cs rename to CustomParameterEditor.Server/Data/ReportDbContext.cs index 0ebc368..cf9bd9a 100644 --- a/CustomParameterEditorAngularExample/Data/ReportDbContext.cs +++ b/CustomParameterEditor.Server/Data/ReportDbContext.cs @@ -1,63 +1,63 @@ -using System.Linq; -using Microsoft.EntityFrameworkCore; - -namespace CustomParameterEditorAngularExample.Data { - public class SqlDataConnectionDescription : DataConnection { } - public class JsonDataConnectionDescription : DataConnection { } - public abstract class DataConnection { - public int Id { get; set; } - public string Name { get; set; } - public string DisplayName { get; set; } - public string ConnectionString { get; set; } - } - - public class ReportItem { - public int Id { get; set; } - public string Name { get; set; } - public string DisplayName { get; set; } - public byte[] LayoutData { get; set; } - } - - public class ReportDbContext : DbContext { - public DbSet JsonDataConnections { get; set; } - public DbSet SqlDataConnections { get; set; } - public DbSet Reports { get; set; } - public ReportDbContext(DbContextOptions options) : base(options) { - } - public void InitializeDatabase() { - Database.EnsureCreated(); - - var nwindJsonDataConnectionName = "NWindProductsJson"; - if(!JsonDataConnections.Any(x => x.Name == nwindJsonDataConnectionName)) { - var newData = new JsonDataConnectionDescription { - Name = nwindJsonDataConnectionName, - DisplayName = "Northwind Products (JSON)", - ConnectionString = "Uri=Data/nwind.json" - }; - JsonDataConnections.Add(newData); - } - - - var nwindSqlDataConnectionName = "NWindConnectionString"; - if(!SqlDataConnections.Any(x => x.Name == nwindSqlDataConnectionName)) { - var newData = new SqlDataConnectionDescription { - Name = nwindSqlDataConnectionName, - DisplayName = "Northwind Data Connection", - ConnectionString = "XpoProvider=SQLite;Data Source=|DataDirectory|Data/nwind.db" - }; - SqlDataConnections.Add(newData); - } - - var reportsDataConnectionName = "ReportsDataSqlite"; - if(!SqlDataConnections.Any(x => x.Name == reportsDataConnectionName)) { - var newData = new SqlDataConnectionDescription { - Name = reportsDataConnectionName, - DisplayName = "Reports Data (Demo)", - ConnectionString = "XpoProvider=SQLite;Data Source=|DataDirectory|Data/reportsData.db" - }; - SqlDataConnections.Add(newData); - } - SaveChanges(); - } - } +using System.Linq; +using Microsoft.EntityFrameworkCore; + +namespace CustomParameterEditor.Data { + public class SqlDataConnectionDescription : DataConnection { } + public class JsonDataConnectionDescription : DataConnection { } + public abstract class DataConnection { + public int Id { get; set; } + public string Name { get; set; } + public string DisplayName { get; set; } + public string ConnectionString { get; set; } + } + + public class ReportItem { + public int Id { get; set; } + public string Name { get; set; } + public string DisplayName { get; set; } + public byte[] LayoutData { get; set; } + } + + public class ReportDbContext : DbContext { + public DbSet JsonDataConnections { get; set; } + public DbSet SqlDataConnections { get; set; } + public DbSet Reports { get; set; } + public ReportDbContext(DbContextOptions options) : base(options) { + } + public void InitializeDatabase() { + Database.EnsureCreated(); + + var nwindJsonDataConnectionName = "NWindProductsJson"; + if(!JsonDataConnections.Any(x => x.Name == nwindJsonDataConnectionName)) { + var newData = new JsonDataConnectionDescription { + Name = nwindJsonDataConnectionName, + DisplayName = "Northwind Products (JSON)", + ConnectionString = "Uri=Data/nwind.json" + }; + JsonDataConnections.Add(newData); + } + + + var nwindSqlDataConnectionName = "NWindConnectionString"; + if(!SqlDataConnections.Any(x => x.Name == nwindSqlDataConnectionName)) { + var newData = new SqlDataConnectionDescription { + Name = nwindSqlDataConnectionName, + DisplayName = "Northwind Data Connection", + ConnectionString = "XpoProvider=SQLite;Data Source=|DataDirectory|Data/nwind.db" + }; + SqlDataConnections.Add(newData); + } + + var reportsDataConnectionName = "ReportsDataSqlite"; + if(!SqlDataConnections.Any(x => x.Name == reportsDataConnectionName)) { + var newData = new SqlDataConnectionDescription { + Name = reportsDataConnectionName, + DisplayName = "Reports Data (Demo)", + ConnectionString = "XpoProvider=SQLite;Data Source=|DataDirectory|Data/reportsData.db" + }; + SqlDataConnections.Add(newData); + } + SaveChanges(); + } + } } \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/Data/reportsData.db b/CustomParameterEditor.Server/Data/reportsData.db similarity index 99% rename from CustomParameterEditorAngularExample/Data/reportsData.db rename to CustomParameterEditor.Server/Data/reportsData.db index 7a11360..c2dd537 100644 Binary files a/CustomParameterEditorAngularExample/Data/reportsData.db and b/CustomParameterEditor.Server/Data/reportsData.db differ diff --git a/CustomParameterEditorAngularExample/Pages/Error.cshtml b/CustomParameterEditor.Server/Pages/Error.cshtml similarity index 97% rename from CustomParameterEditorAngularExample/Pages/Error.cshtml rename to CustomParameterEditor.Server/Pages/Error.cshtml index 4913341..b1f3143 100644 --- a/CustomParameterEditorAngularExample/Pages/Error.cshtml +++ b/CustomParameterEditor.Server/Pages/Error.cshtml @@ -1,23 +1,23 @@ -@page -@model ErrorModel -@{ - ViewData["Title"] = "Error"; -} - -

Error.

-

An error occurred while processing your request.

- -@if (Model.ShowRequestId) -{ -

- Request ID: @Model.RequestId -

-} - -

Development Mode

-

- Swapping to Development environment will display more detailed information about the error that occurred. -

-

- Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. -

+@page +@model ErrorModel +@{ + ViewData["Title"] = "Error"; +} + +

Error.

+

An error occurred while processing your request.

+ +@if (Model.ShowRequestId) +{ +

+ Request ID: @Model.RequestId +

+} + +

Development Mode

+

+ Swapping to Development environment will display more detailed information about the error that occurred. +

+

+ Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. +

diff --git a/CustomParameterEditorAngularExample/Pages/Error.cshtml.cs b/CustomParameterEditor.Server/Pages/Error.cshtml.cs similarity index 88% rename from CustomParameterEditorAngularExample/Pages/Error.cshtml.cs rename to CustomParameterEditor.Server/Pages/Error.cshtml.cs index 18073a6..daf7a65 100644 --- a/CustomParameterEditorAngularExample/Pages/Error.cshtml.cs +++ b/CustomParameterEditor.Server/Pages/Error.cshtml.cs @@ -1,23 +1,23 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; - -namespace CustomParameterEditorAngularExample.Pages -{ - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] - public class ErrorModel : PageModel - { - public string RequestId { get; set; } - - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - - public void OnGet() - { - RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; - } - } -} \ No newline at end of file +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace CustomParameterEditor.Pages +{ + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + public class ErrorModel : PageModel + { + public string RequestId { get; set; } + + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + public void OnGet() + { + RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; + } + } +} diff --git a/CustomParameterEditor.Server/Pages/_ViewImports.cshtml b/CustomParameterEditor.Server/Pages/_ViewImports.cshtml new file mode 100644 index 0000000..b8d7314 --- /dev/null +++ b/CustomParameterEditor.Server/Pages/_ViewImports.cshtml @@ -0,0 +1,3 @@ +@using CustomParameterEditor +@namespace CustomParameterEditor.Pages +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/CustomParameterEditorAngularExample/PredefinedReports/CustomParameterReport.Designer.cs b/CustomParameterEditor.Server/PredefinedReports/CustomParameterReport.Designer.cs similarity index 97% rename from CustomParameterEditorAngularExample/PredefinedReports/CustomParameterReport.Designer.cs rename to CustomParameterEditor.Server/PredefinedReports/CustomParameterReport.Designer.cs index c8b9837..17510e9 100644 --- a/CustomParameterEditorAngularExample/PredefinedReports/CustomParameterReport.Designer.cs +++ b/CustomParameterEditor.Server/PredefinedReports/CustomParameterReport.Designer.cs @@ -1,177 +1,177 @@ -namespace CustomParameterEditorAngularExample.PredefinedReports -{ - partial class CustomParameterReport - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.TopMargin = new DevExpress.XtraReports.UI.TopMarginBand(); - this.Detail = new DevExpress.XtraReports.UI.DetailBand(); - this.label2 = new DevExpress.XtraReports.UI.XRLabel(); - this.xrLabel10 = new DevExpress.XtraReports.UI.XRLabel(); - this.BottomMargin = new DevExpress.XtraReports.UI.BottomMarginBand(); - this.Title = new DevExpress.XtraReports.UI.XRControlStyle(); - this.DetailCaption3 = new DevExpress.XtraReports.UI.XRControlStyle(); - this.DetailData3 = new DevExpress.XtraReports.UI.XRControlStyle(); - this.DetailData3_Odd = new DevExpress.XtraReports.UI.XRControlStyle(); - this.DetailCaptionBackground3 = new DevExpress.XtraReports.UI.XRControlStyle(); - this.PageInfo = new DevExpress.XtraReports.UI.XRControlStyle(); - ((System.ComponentModel.ISupportInitialize)(this)).BeginInit(); - // - // TopMargin - // - this.TopMargin.HeightF = 78F; - this.TopMargin.Name = "TopMargin"; - this.TopMargin.Padding = new DevExpress.XtraPrinting.PaddingInfo(0, 0, 0, 0, 100F); - this.TopMargin.TextAlignment = DevExpress.XtraPrinting.TextAlignment.TopLeft; - // - // Detail - // - this.Detail.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] { - this.label2, - this.xrLabel10}); - this.Detail.HeightF = 289.72F; - this.Detail.KeepTogether = true; - this.Detail.Name = "Detail"; - this.Detail.Padding = new DevExpress.XtraPrinting.PaddingInfo(0, 0, 0, 0, 100F); - this.Detail.TextAlignment = DevExpress.XtraPrinting.TextAlignment.TopLeft; - // - // label2 - // - this.label2.LocationFloat = new DevExpress.Utils.PointFloat(179.5133F, 52.70001F); - this.label2.Multiline = true; - this.label2.Name = "label2"; - this.label2.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); - this.label2.SizeF = new System.Drawing.SizeF(262.55F, 28.22F); - // - // xrLabel10 - // - this.xrLabel10.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F); - this.xrLabel10.Multiline = true; - this.xrLabel10.Name = "xrLabel10"; - this.xrLabel10.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); - this.xrLabel10.SizeF = new System.Drawing.SizeF(249.4583F, 25.55338F); - this.xrLabel10.StyleName = "Title"; - this.xrLabel10.Text = "Send this report to:"; - // - // BottomMargin - // - this.BottomMargin.Name = "BottomMargin"; - this.BottomMargin.Padding = new DevExpress.XtraPrinting.PaddingInfo(0, 0, 0, 0, 100F); - this.BottomMargin.TextAlignment = DevExpress.XtraPrinting.TextAlignment.TopLeft; - // - // Title - // - this.Title.BackColor = System.Drawing.Color.Transparent; - this.Title.BorderColor = System.Drawing.Color.Black; - this.Title.Borders = DevExpress.XtraPrinting.BorderSide.None; - this.Title.BorderWidth = 1F; - this.Title.Font = new DevExpress.Drawing.DXFont("Tahoma", 14F); - this.Title.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(75)))), ((int)(((byte)(75)))), ((int)(((byte)(75))))); - this.Title.Name = "Title"; - // - // DetailCaption3 - // - this.DetailCaption3.BackColor = System.Drawing.Color.Transparent; - this.DetailCaption3.BorderColor = System.Drawing.Color.Transparent; - this.DetailCaption3.Borders = DevExpress.XtraPrinting.BorderSide.None; - this.DetailCaption3.Font = new DevExpress.Drawing.DXFont("Tahoma", 8F, DevExpress.Drawing.DXFontStyle.Bold); - this.DetailCaption3.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(75)))), ((int)(((byte)(75)))), ((int)(((byte)(75))))); - this.DetailCaption3.Name = "DetailCaption3"; - this.DetailCaption3.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F); - this.DetailCaption3.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft; - // - // DetailData3 - // - this.DetailData3.Font = new DevExpress.Drawing.DXFont("Tahoma", 8F); - this.DetailData3.ForeColor = System.Drawing.Color.Black; - this.DetailData3.Name = "DetailData3"; - this.DetailData3.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F); - this.DetailData3.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft; - // - // DetailData3_Odd - // - this.DetailData3_Odd.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(231)))), ((int)(((byte)(231)))), ((int)(((byte)(231))))); - this.DetailData3_Odd.BorderColor = System.Drawing.Color.Transparent; - this.DetailData3_Odd.Borders = DevExpress.XtraPrinting.BorderSide.None; - this.DetailData3_Odd.BorderWidth = 1F; - this.DetailData3_Odd.Font = new DevExpress.Drawing.DXFont("Tahoma", 8F); - this.DetailData3_Odd.ForeColor = System.Drawing.Color.Black; - this.DetailData3_Odd.Name = "DetailData3_Odd"; - this.DetailData3_Odd.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F); - this.DetailData3_Odd.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft; - // - // DetailCaptionBackground3 - // - this.DetailCaptionBackground3.BackColor = System.Drawing.Color.Transparent; - this.DetailCaptionBackground3.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(206)))), ((int)(((byte)(206)))), ((int)(((byte)(206))))); - this.DetailCaptionBackground3.Borders = DevExpress.XtraPrinting.BorderSide.Top; - this.DetailCaptionBackground3.BorderWidth = 2F; - this.DetailCaptionBackground3.Name = "DetailCaptionBackground3"; - // - // PageInfo - // - this.PageInfo.Font = new DevExpress.Drawing.DXFont("Tahoma", 8F, DevExpress.Drawing.DXFontStyle.Bold); - this.PageInfo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(75)))), ((int)(((byte)(75)))), ((int)(((byte)(75))))); - this.PageInfo.Name = "PageInfo"; - this.PageInfo.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); - // - // CustomParameterReport - // - this.Bands.AddRange(new DevExpress.XtraReports.UI.Band[] { - this.TopMargin, - this.Detail, - this.BottomMargin}); - this.DisplayName = "CustomParameterReport"; - this.Extensions.Add("DataSerializationExtension", "myCustomDataSerializer"); - this.Margins = new DevExpress.Drawing.DXMargins(100F, 100F, 78F, 100F); - this.StyleSheet.AddRange(new DevExpress.XtraReports.UI.XRControlStyle[] { - this.Title, - this.DetailCaption3, - this.DetailData3, - this.DetailData3_Odd, - this.DetailCaptionBackground3, - this.PageInfo}); - this.Version = "23.2"; - ((System.ComponentModel.ISupportInitialize)(this)).EndInit(); - - } - - #endregion - - private DevExpress.XtraReports.UI.TopMarginBand TopMargin; - private DevExpress.XtraReports.UI.DetailBand Detail; - private DevExpress.XtraReports.UI.XRLabel label2; - private DevExpress.XtraReports.UI.XRLabel xrLabel10; - private DevExpress.XtraReports.UI.BottomMarginBand BottomMargin; - private DevExpress.XtraReports.UI.XRControlStyle Title; - private DevExpress.XtraReports.UI.XRControlStyle DetailCaption3; - private DevExpress.XtraReports.UI.XRControlStyle DetailData3; - private DevExpress.XtraReports.UI.XRControlStyle DetailData3_Odd; - private DevExpress.XtraReports.UI.XRControlStyle DetailCaptionBackground3; - private DevExpress.XtraReports.UI.XRControlStyle PageInfo; - } -} +namespace CustomParameterEditor.Server.PredefinedReports +{ + partial class CustomParameterReport + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.TopMargin = new DevExpress.XtraReports.UI.TopMarginBand(); + this.Detail = new DevExpress.XtraReports.UI.DetailBand(); + this.label2 = new DevExpress.XtraReports.UI.XRLabel(); + this.xrLabel10 = new DevExpress.XtraReports.UI.XRLabel(); + this.BottomMargin = new DevExpress.XtraReports.UI.BottomMarginBand(); + this.Title = new DevExpress.XtraReports.UI.XRControlStyle(); + this.DetailCaption3 = new DevExpress.XtraReports.UI.XRControlStyle(); + this.DetailData3 = new DevExpress.XtraReports.UI.XRControlStyle(); + this.DetailData3_Odd = new DevExpress.XtraReports.UI.XRControlStyle(); + this.DetailCaptionBackground3 = new DevExpress.XtraReports.UI.XRControlStyle(); + this.PageInfo = new DevExpress.XtraReports.UI.XRControlStyle(); + ((System.ComponentModel.ISupportInitialize)(this)).BeginInit(); + // + // TopMargin + // + this.TopMargin.HeightF = 78F; + this.TopMargin.Name = "TopMargin"; + this.TopMargin.Padding = new DevExpress.XtraPrinting.PaddingInfo(0, 0, 0, 0, 100F); + this.TopMargin.TextAlignment = DevExpress.XtraPrinting.TextAlignment.TopLeft; + // + // Detail + // + this.Detail.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] { + this.label2, + this.xrLabel10}); + this.Detail.HeightF = 289.72F; + this.Detail.KeepTogether = true; + this.Detail.Name = "Detail"; + this.Detail.Padding = new DevExpress.XtraPrinting.PaddingInfo(0, 0, 0, 0, 100F); + this.Detail.TextAlignment = DevExpress.XtraPrinting.TextAlignment.TopLeft; + // + // label2 + // + this.label2.LocationFloat = new DevExpress.Utils.PointFloat(179.5133F, 52.70001F); + this.label2.Multiline = true; + this.label2.Name = "label2"; + this.label2.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); + this.label2.SizeF = new System.Drawing.SizeF(262.55F, 28.22F); + // + // xrLabel10 + // + this.xrLabel10.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F); + this.xrLabel10.Multiline = true; + this.xrLabel10.Name = "xrLabel10"; + this.xrLabel10.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); + this.xrLabel10.SizeF = new System.Drawing.SizeF(249.4583F, 25.55338F); + this.xrLabel10.StyleName = "Title"; + this.xrLabel10.Text = "Send this report to:"; + // + // BottomMargin + // + this.BottomMargin.Name = "BottomMargin"; + this.BottomMargin.Padding = new DevExpress.XtraPrinting.PaddingInfo(0, 0, 0, 0, 100F); + this.BottomMargin.TextAlignment = DevExpress.XtraPrinting.TextAlignment.TopLeft; + // + // Title + // + this.Title.BackColor = System.Drawing.Color.Transparent; + this.Title.BorderColor = System.Drawing.Color.Black; + this.Title.Borders = DevExpress.XtraPrinting.BorderSide.None; + this.Title.BorderWidth = 1F; + this.Title.Font = new DevExpress.Drawing.DXFont("Tahoma", 14F); + this.Title.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(75)))), ((int)(((byte)(75)))), ((int)(((byte)(75))))); + this.Title.Name = "Title"; + // + // DetailCaption3 + // + this.DetailCaption3.BackColor = System.Drawing.Color.Transparent; + this.DetailCaption3.BorderColor = System.Drawing.Color.Transparent; + this.DetailCaption3.Borders = DevExpress.XtraPrinting.BorderSide.None; + this.DetailCaption3.Font = new DevExpress.Drawing.DXFont("Tahoma", 8F, DevExpress.Drawing.DXFontStyle.Bold); + this.DetailCaption3.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(75)))), ((int)(((byte)(75)))), ((int)(((byte)(75))))); + this.DetailCaption3.Name = "DetailCaption3"; + this.DetailCaption3.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F); + this.DetailCaption3.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft; + // + // DetailData3 + // + this.DetailData3.Font = new DevExpress.Drawing.DXFont("Tahoma", 8F); + this.DetailData3.ForeColor = System.Drawing.Color.Black; + this.DetailData3.Name = "DetailData3"; + this.DetailData3.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F); + this.DetailData3.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft; + // + // DetailData3_Odd + // + this.DetailData3_Odd.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(231)))), ((int)(((byte)(231)))), ((int)(((byte)(231))))); + this.DetailData3_Odd.BorderColor = System.Drawing.Color.Transparent; + this.DetailData3_Odd.Borders = DevExpress.XtraPrinting.BorderSide.None; + this.DetailData3_Odd.BorderWidth = 1F; + this.DetailData3_Odd.Font = new DevExpress.Drawing.DXFont("Tahoma", 8F); + this.DetailData3_Odd.ForeColor = System.Drawing.Color.Black; + this.DetailData3_Odd.Name = "DetailData3_Odd"; + this.DetailData3_Odd.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F); + this.DetailData3_Odd.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft; + // + // DetailCaptionBackground3 + // + this.DetailCaptionBackground3.BackColor = System.Drawing.Color.Transparent; + this.DetailCaptionBackground3.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(206)))), ((int)(((byte)(206)))), ((int)(((byte)(206))))); + this.DetailCaptionBackground3.Borders = DevExpress.XtraPrinting.BorderSide.Top; + this.DetailCaptionBackground3.BorderWidth = 2F; + this.DetailCaptionBackground3.Name = "DetailCaptionBackground3"; + // + // PageInfo + // + this.PageInfo.Font = new DevExpress.Drawing.DXFont("Tahoma", 8F, DevExpress.Drawing.DXFontStyle.Bold); + this.PageInfo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(75)))), ((int)(((byte)(75)))), ((int)(((byte)(75))))); + this.PageInfo.Name = "PageInfo"; + this.PageInfo.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); + // + // CustomParameterReport + // + this.Bands.AddRange(new DevExpress.XtraReports.UI.Band[] { + this.TopMargin, + this.Detail, + this.BottomMargin}); + this.DisplayName = "CustomParameterReport"; + this.Extensions.Add("DataSerializationExtension", "myCustomDataSerializer"); + this.Margins = new DevExpress.Drawing.DXMargins(100F, 100F, 78F, 100F); + this.StyleSheet.AddRange(new DevExpress.XtraReports.UI.XRControlStyle[] { + this.Title, + this.DetailCaption3, + this.DetailData3, + this.DetailData3_Odd, + this.DetailCaptionBackground3, + this.PageInfo}); + this.Version = "25.2"; + ((System.ComponentModel.ISupportInitialize)(this)).EndInit(); + + } + + #endregion + + private DevExpress.XtraReports.UI.TopMarginBand TopMargin; + private DevExpress.XtraReports.UI.DetailBand Detail; + private DevExpress.XtraReports.UI.XRLabel label2; + private DevExpress.XtraReports.UI.XRLabel xrLabel10; + private DevExpress.XtraReports.UI.BottomMarginBand BottomMargin; + private DevExpress.XtraReports.UI.XRControlStyle Title; + private DevExpress.XtraReports.UI.XRControlStyle DetailCaption3; + private DevExpress.XtraReports.UI.XRControlStyle DetailData3; + private DevExpress.XtraReports.UI.XRControlStyle DetailData3_Odd; + private DevExpress.XtraReports.UI.XRControlStyle DetailCaptionBackground3; + private DevExpress.XtraReports.UI.XRControlStyle PageInfo; + } +} diff --git a/CustomParameterEditorAngularExample/PredefinedReports/CustomParameterReport.cs b/CustomParameterEditor.Server/PredefinedReports/CustomParameterReport.cs similarity index 90% rename from CustomParameterEditorAngularExample/PredefinedReports/CustomParameterReport.cs rename to CustomParameterEditor.Server/PredefinedReports/CustomParameterReport.cs index 3fb10ad..035238d 100644 --- a/CustomParameterEditorAngularExample/PredefinedReports/CustomParameterReport.cs +++ b/CustomParameterEditor.Server/PredefinedReports/CustomParameterReport.cs @@ -1,28 +1,28 @@ -using DevExpress.XtraReports.Parameters; -using DevExpress.XtraReports.UI; -using System; - -namespace CustomParameterEditorAngularExample.PredefinedReports { - public partial class CustomParameterReport : DevExpress.XtraReports.UI.XtraReport { - public CustomParameterReport() { - InitializeComponent(); - - // - // customMailParameter - // - Parameter customMailParameter = new Parameter { - Description = "Custom Email Parameter", - Name = "customMailParameter", - ValueInfo = "SampleMail@example.com", - Type = typeof(CustomParameterType), - Visible = true, - Enabled = true - }; - - this.Parameters.Add(customMailParameter); - - this.label2.ExpressionBindings.AddRange(new ExpressionBinding[] { - new ExpressionBinding("BeforePrint", "Text", "?customMailParameter") }); - } - } -} +using DevExpress.XtraReports.Parameters; +using DevExpress.XtraReports.UI; +using System; + +namespace CustomParameterEditor.Server.PredefinedReports { + public partial class CustomParameterReport : DevExpress.XtraReports.UI.XtraReport { + public CustomParameterReport() { + InitializeComponent(); + + // + // customMailParameter + // + Parameter customMailParameter = new Parameter { + Description = "Custom Email Parameter", + Name = "customMailParameter", + ValueInfo = "SampleMail@example.com", + Type = typeof(CustomParameterType), + Visible = true, + Enabled = true + }; + + this.Parameters.Add(customMailParameter); + + this.label2.ExpressionBindings.AddRange(new ExpressionBinding[] { + new ExpressionBinding("BeforePrint", "Text", "?customMailParameter") }); + } + } +} diff --git a/CustomParameterEditorAngularExample/PredefinedReports/CustomParameterReport.resx b/CustomParameterEditor.Server/PredefinedReports/CustomParameterReport.resx similarity index 97% rename from CustomParameterEditorAngularExample/PredefinedReports/CustomParameterReport.resx rename to CustomParameterEditor.Server/PredefinedReports/CustomParameterReport.resx index 29dcb1b..1af7de1 100644 --- a/CustomParameterEditorAngularExample/PredefinedReports/CustomParameterReport.resx +++ b/CustomParameterEditor.Server/PredefinedReports/CustomParameterReport.resx @@ -1,120 +1,120 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/PredefinedReports/ReportsFactory.cs b/CustomParameterEditor.Server/PredefinedReports/ReportsFactory.cs similarity index 83% rename from CustomParameterEditorAngularExample/PredefinedReports/ReportsFactory.cs rename to CustomParameterEditor.Server/PredefinedReports/ReportsFactory.cs index 9d0acdd..520d2a8 100644 --- a/CustomParameterEditorAngularExample/PredefinedReports/ReportsFactory.cs +++ b/CustomParameterEditor.Server/PredefinedReports/ReportsFactory.cs @@ -1,16 +1,16 @@ -using DevExpress.XtraReports.UI; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace CustomParameterEditorAngularExample.PredefinedReports -{ - public static class ReportsFactory - { - public static Dictionary> Reports = new Dictionary>() - { - ["CustomParameterReport"] = () => new CustomParameterReport() - }; - } +using DevExpress.XtraReports.UI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace CustomParameterEditor.Server.PredefinedReports +{ + public static class ReportsFactory + { + public static Dictionary> Reports = new Dictionary>() + { + ["CustomParameterReport"] = () => new CustomParameterReport() + }; + } } \ No newline at end of file diff --git a/CustomParameterEditor.Server/Program.cs b/CustomParameterEditor.Server/Program.cs new file mode 100644 index 0000000..1661012 --- /dev/null +++ b/CustomParameterEditor.Server/Program.cs @@ -0,0 +1,52 @@ +using CustomParameterEditor; +using CustomParameterEditor.Data; +using CustomParameterEditor.Server.Services; +using DevExpress.AspNetCore; +using DevExpress.AspNetCore.Reporting; +using DevExpress.Security.Resources; +using DevExpress.XtraReports.Native; +using DevExpress.XtraReports.Web.Extensions; +using Microsoft.EntityFrameworkCore; + + +DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(CustomParameterType)); +DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(CustomParameterType[])); +SerializationService.RegisterSerializer(CustomDataSerializer.Name, new CustomDataSerializer()); + +var builder = WebApplication.CreateBuilder(args); + +AppDomain.CurrentDomain.SetData("DataDirectory", builder.Environment.ContentRootPath); +builder.Services.AddDevExpressControls(); +builder.Services.AddScoped(); +builder.Services.AddMvc(); +builder.Services.ConfigureReportingServices(configurator => { + if(builder.Environment.IsDevelopment()) + configurator.UseDevelopmentMode(); + configurator.ConfigureWebDocumentViewer(viewerConfigurator => { + viewerConfigurator.UseCachedReportSourceBuilder(); + }); +}); +builder.Services.AddDbContext(options => options.UseSqlite(builder.Configuration.GetConnectionString("ReportsDataConnectionString"))); + +var app = builder.Build(); +using(var scope = app.Services.CreateScope()) { + var services = scope.ServiceProvider; + services.GetService().InitializeDatabase(); +} +var contentDirectoryAllowRule = DirectoryAccessRule.Allow(new DirectoryInfo(Path.Combine(app.Environment.ContentRootPath, "Content")).FullName); +AccessSettings.ReportingSpecificResources.SetRules(contentDirectoryAllowRule, UrlAccessRule.Deny()); + +app.UseHttpsRedirection(); +app.UseStaticFiles(); +app.UseRouting(); + + +app.UseDevExpressControls(); +System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12; +app.MapControllerRoute( + name: "default", + pattern: "{controller}/{action=Index}/{id?}"); + +app.MapFallbackToFile("/index.html"); + +app.Run(); \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/Reports/CustomParameterReport.repx b/CustomParameterEditor.Server/Reports/CustomParameterReport.repx similarity index 99% rename from CustomParameterEditorAngularExample/Reports/CustomParameterReport.repx rename to CustomParameterEditor.Server/Reports/CustomParameterReport.repx index 79d31c0..3953c84 100644 --- a/CustomParameterEditorAngularExample/Reports/CustomParameterReport.repx +++ b/CustomParameterEditor.Server/Reports/CustomParameterReport.repx @@ -1,80 +1,80 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/Services/CustomDataSerializer.cs b/CustomParameterEditor.Server/Services/CustomDataSerializer.cs similarity index 81% rename from CustomParameterEditorAngularExample/Services/CustomDataSerializer.cs rename to CustomParameterEditor.Server/Services/CustomDataSerializer.cs index 4e69146..cc66b4a 100644 --- a/CustomParameterEditorAngularExample/Services/CustomDataSerializer.cs +++ b/CustomParameterEditor.Server/Services/CustomDataSerializer.cs @@ -1,33 +1,29 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using CustomParameterEditorAngularExample; -using DevExpress.XtraReports.Native; - -namespace CustomParameterEditorAngularExample { - [TypeConverter(typeof(CustomParameterTypeConverter))] - public class CustomDataSerializer : IDataSerializer { - public const string Name = "myCustomDataSerializer"; - - public bool CanDeserialize(string value, string typeName, object extensionProvider) { - return typeName == typeof(CustomParameterType).FullName; - } - - public bool CanSerialize(object data, object extensionProvider) { - return data is CustomParameterType; - } - - public object Deserialize(string value, string typeName, object extensionProvider) { - if (typeName == typeof(CustomParameterType).FullName) { - return new CustomParameterType { Value = value }; - } - return null; - } - - public string Serialize(object data, object extensionProvider) { - var parameter = data as CustomParameterType; - return parameter != null ? parameter.Value : null; - } - } +using DevExpress.XtraReports.Native; +using System.ComponentModel; + +namespace CustomParameterEditor { + [TypeConverter(typeof(CustomParameterTypeConverter))] + public class CustomDataSerializer : IDataSerializer { + public const string Name = "myCustomDataSerializer"; + + public bool CanDeserialize(string value, string typeName, object extensionProvider) { + return typeName == typeof(CustomParameterType).FullName; + } + + public bool CanSerialize(object data, object extensionProvider) { + return data is CustomParameterType; + } + + public object Deserialize(string value, string typeName, object extensionProvider) { + if (typeName == typeof(CustomParameterType).FullName) { + return new CustomParameterType { Value = value }; + } + return null; + } + + public string Serialize(object data, object extensionProvider) { + var parameter = data as CustomParameterType; + return parameter != null ? parameter.Value : null; + } + } } \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/Services/CustomParameterType.cs b/CustomParameterEditor.Server/Services/CustomParameterType.cs similarity index 97% rename from CustomParameterEditorAngularExample/Services/CustomParameterType.cs rename to CustomParameterEditor.Server/Services/CustomParameterType.cs index 00b21d2..5ed9132 100644 --- a/CustomParameterEditorAngularExample/Services/CustomParameterType.cs +++ b/CustomParameterEditor.Server/Services/CustomParameterType.cs @@ -1,38 +1,38 @@ -using System; -using System.ComponentModel; -using System.Globalization; - -[TypeConverter(typeof(CustomParameterTypeConverter))] -public class CustomParameterType { - public string Value { get; set; } - public override string ToString() { - return Value; - } -} - -public class CustomParameterTypeConverter : TypeConverter { - public override object ConvertTo(ITypeDescriptorContext context, - CultureInfo culture, object value, Type destinationType) { - if (destinationType == typeof(string)) { - return ((CustomParameterType)value).Value; - } - return base.ConvertTo(context, culture, value, destinationType); - } - public override bool CanConvertTo(ITypeDescriptorContext context, - Type destinationType) { - return destinationType == typeof(string) || - base.CanConvertTo(context, destinationType); - } - - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - public override object ConvertFrom(ITypeDescriptorContext context, - CultureInfo culture, object value) { - var valueString = value as string; - if (valueString != null) { - return new CustomParameterType { Value = valueString }; - } - return base.ConvertFrom(context, culture, value); - } +using System; +using System.ComponentModel; +using System.Globalization; + +[TypeConverter(typeof(CustomParameterTypeConverter))] +public class CustomParameterType { + public string Value { get; set; } + public override string ToString() { + return Value; + } +} + +public class CustomParameterTypeConverter : TypeConverter { + public override object ConvertTo(ITypeDescriptorContext context, + CultureInfo culture, object value, Type destinationType) { + if (destinationType == typeof(string)) { + return ((CustomParameterType)value).Value; + } + return base.ConvertTo(context, culture, value, destinationType); + } + public override bool CanConvertTo(ITypeDescriptorContext context, + Type destinationType) { + return destinationType == typeof(string) || + base.CanConvertTo(context, destinationType); + } + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + public override object ConvertFrom(ITypeDescriptorContext context, + CultureInfo culture, object value) { + var valueString = value as string; + if (valueString != null) { + return new CustomParameterType { Value = valueString }; + } + return base.ConvertFrom(context, culture, value); + } } \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/Services/CustomReportStorageWebExtension.cs b/CustomParameterEditor.Server/Services/CustomReportStorageWebExtension.cs similarity index 90% rename from CustomParameterEditorAngularExample/Services/CustomReportStorageWebExtension.cs rename to CustomParameterEditor.Server/Services/CustomReportStorageWebExtension.cs index 6dae555..1a820fe 100644 --- a/CustomParameterEditorAngularExample/Services/CustomReportStorageWebExtension.cs +++ b/CustomParameterEditor.Server/Services/CustomReportStorageWebExtension.cs @@ -1,84 +1,80 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using DevExpress.XtraReports.UI; -using CustomParameterEditorAngularExample.PredefinedReports; -using CustomParameterEditorAngularExample.Data; - -namespace CustomParameterEditorAngularExample.Services -{ - public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension - { - protected ReportDbContext DbContext { get; set; } - public CustomReportStorageWebExtension(ReportDbContext dbContext) { - this.DbContext = dbContext; - } - - public override bool CanSetData(string url) { - // Determines whether a report with the specified URL can be saved. - // Add custom logic that returns **false** for reports that should be read-only. - // Return **true** if no valdation is required. - // This method is called only for valid URLs (if the **IsValidUrl** method returns **true**). - - return true; - } - - public override bool IsValidUrl(string url) { - // Determines whether the URL passed to the current report storage is valid. - // Implement your own logic to prohibit URLs that contain spaces or other specific characters. - // Return **true** if no validation is required. - - return true; - } - - public override byte[] GetData(string url) { - // Uses a specified URL to return report layout data stored within a report storage medium. - // This method is called if the **IsValidUrl** method returns **true**. - // You can use the **GetData** method to process report parameters sent from the client - // if the parameters are included in the report URL's query string. - var reportData = DbContext.Reports.FirstOrDefault(x => x.Name == url); - if(reportData != null) - return reportData.LayoutData; - - if(ReportsFactory.Reports.ContainsKey(url)) { - using var ms = new MemoryStream(); - using XtraReport report = ReportsFactory.Reports[url](); - report.SaveLayoutToXml(ms); - return ms.ToArray(); - } - throw new DevExpress.XtraReports.Web.ClientControls.FaultException(string.Format("Could not find report '{0}'.", url)); - } - - public override Dictionary GetUrls() { - // Returns a dictionary that contains the report names (URLs) and display names. - // The Report Designer uses this method to populate the Open Report and Save Report dialogs. - - return DbContext.Reports - .ToList() - .Select(x => x.Name) - .Union(ReportsFactory.Reports.Select(x => x.Key)) - .ToDictionary(x => x); - } - - public override void SetData(XtraReport report, string url) { - // Saves the specified report to the report storage with the specified name - // (saves existing reports only). - using var stream = new MemoryStream(); report.SaveLayoutToXml(stream); - var reportData = DbContext.Reports.FirstOrDefault(x => x.Name == url); - if(reportData == null) { - DbContext.Reports.Add(new ReportItem { Name = url, LayoutData = stream.ToArray() }); - } else { - reportData.LayoutData = stream.ToArray(); - } - DbContext.SaveChanges(); - } - - public override string SetNewData(XtraReport report, string defaultUrl) { - // Allows you to validate and correct the specified name (URL). - // This method also allows you to return the resulting name (URL), - // and to save your report to a storage. The method is called only for new reports. - SetData(report, defaultUrl); - return defaultUrl; - } - } +using CustomParameterEditor.Data; +using CustomParameterEditor.Server.PredefinedReports; +using DevExpress.XtraReports.UI; + + +namespace CustomParameterEditor.Server.Services { + public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension { + protected ReportDbContext DbContext { get; set; } + public CustomReportStorageWebExtension(ReportDbContext dbContext) { + this.DbContext = dbContext; + } + + public override bool CanSetData(string url) { + // Determines whether a report with the specified URL can be saved. + // Add custom logic that returns **false** for reports that should be read-only. + // Return **true** if no valdation is required. + // This method is called only for valid URLs (if the **IsValidUrl** method returns **true**). + + return true; + } + + public override bool IsValidUrl(string url) { + // Determines whether the URL passed to the current report storage is valid. + // Implement your own logic to prohibit URLs that contain spaces or other specific characters. + // Return **true** if no validation is required. + + return true; + } + + public override byte[] GetData(string url) { + // Uses a specified URL to return report layout data stored within a report storage medium. + // This method is called if the **IsValidUrl** method returns **true**. + // You can use the **GetData** method to process report parameters sent from the client + // if the parameters are included in the report URL's query string. + var reportData = DbContext.Reports.FirstOrDefault(x => x.Name == url); + if(reportData != null) + return reportData.LayoutData; + + if(ReportsFactory.Reports.ContainsKey(url)) { + using var ms = new MemoryStream(); + using XtraReport report = ReportsFactory.Reports[url](); + report.SaveLayoutToXml(ms); + return ms.ToArray(); + } + throw new DevExpress.XtraReports.Web.ClientControls.FaultException(string.Format("Could not find report '{0}'.", url)); + } + + public override Dictionary GetUrls() { + // Returns a dictionary that contains the report names (URLs) and display names. + // The Report Designer uses this method to populate the Open Report and Save Report dialogs. + + return DbContext.Reports + .ToList() + .Select(x => x.Name) + .Union(ReportsFactory.Reports.Select(x => x.Key)) + .ToDictionary(x => x); + } + + public override void SetData(XtraReport report, string url) { + // Saves the specified report to the report storage with the specified name + // (saves existing reports only). + using var stream = new MemoryStream(); report.SaveLayoutToXml(stream); + var reportData = DbContext.Reports.FirstOrDefault(x => x.Name == url); + if(reportData == null) { + DbContext.Reports.Add(new ReportItem { Name = url, LayoutData = stream.ToArray() }); + } else { + reportData.LayoutData = stream.ToArray(); + } + DbContext.SaveChanges(); + } + + public override string SetNewData(XtraReport report, string defaultUrl) { + // Allows you to validate and correct the specified name (URL). + // This method also allows you to return the resulting name (URL), + // and to save your report to a storage. The method is called only for new reports. + SetData(report, defaultUrl); + return defaultUrl; + } + } } \ No newline at end of file diff --git a/CustomParameterEditor.Server/appsettings.Development.json b/CustomParameterEditor.Server/appsettings.Development.json new file mode 100644 index 0000000..cc7fe77 --- /dev/null +++ b/CustomParameterEditor.Server/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "System": "Information", + "Microsoft": "Information", + "DevExpress": "Information" + } + } +} diff --git a/CustomParameterEditor.Server/appsettings.json b/CustomParameterEditor.Server/appsettings.json new file mode 100644 index 0000000..2f226ec --- /dev/null +++ b/CustomParameterEditor.Server/appsettings.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "DevExpress": "Warning" + } + }, + "ConnectionStrings": { + "NWindConnectionString": "XpoProvider=SQLite;Data Source=|DataDirectory|Data/nwind.db", + "ReportsDataConnectionString": "Filename=Data/reportsData.db" + } +} diff --git a/CustomParameterEditor.sln b/CustomParameterEditor.sln new file mode 100644 index 0000000..28e30b4 --- /dev/null +++ b/CustomParameterEditor.sln @@ -0,0 +1,33 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 18 +VisualStudioVersion = 18.4.11620.152 stable +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomParameterEditor.Server", "CustomParameterEditor.Server\CustomParameterEditor.Server.csproj", "{FB117C1D-BFB3-4D7A-AAD1-042CCDDC4512}" +EndProject +Project("{54A90642-561A-4BB1-A94E-469ADEE60C69}") = "CustomParameterEditor.client", "CustomParameterEditor.Client\CustomParameterEditor.client.esproj", "{11060F51-A910-4D64-AB29-2D21457C9397}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FB117C1D-BFB3-4D7A-AAD1-042CCDDC4512}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB117C1D-BFB3-4D7A-AAD1-042CCDDC4512}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB117C1D-BFB3-4D7A-AAD1-042CCDDC4512}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB117C1D-BFB3-4D7A-AAD1-042CCDDC4512}.Release|Any CPU.Build.0 = Release|Any CPU + {11060F51-A910-4D64-AB29-2D21457C9397}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11060F51-A910-4D64-AB29-2D21457C9397}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11060F51-A910-4D64-AB29-2D21457C9397}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {11060F51-A910-4D64-AB29-2D21457C9397}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11060F51-A910-4D64-AB29-2D21457C9397}.Release|Any CPU.Build.0 = Release|Any CPU + {11060F51-A910-4D64-AB29-2D21457C9397}.Release|Any CPU.Deploy.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1B213E3C-EDDB-4978-B747-DA43AB9A66B9} + EndGlobalSection +EndGlobal diff --git a/CustomParameterEditorAngularExample.sln b/CustomParameterEditorAngularExample.sln deleted file mode 100644 index 5fe8850..0000000 --- a/CustomParameterEditorAngularExample.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.9.34723.18 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomParameterEditorAngularExample", "CustomParameterEditorAngularExample\CustomParameterEditorAngularExample.csproj", "{27107B6F-E2C2-420E-849F-364115C20E46}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {27107B6F-E2C2-420E-849F-364115C20E46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {27107B6F-E2C2-420E-849F-364115C20E46}.Debug|Any CPU.Build.0 = Debug|Any CPU - {27107B6F-E2C2-420E-849F-364115C20E46}.Release|Any CPU.ActiveCfg = Release|Any CPU - {27107B6F-E2C2-420E-849F-364115C20E46}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {59B2F8B9-5173-4589-854E-434388615175} - EndGlobalSection -EndGlobal diff --git a/CustomParameterEditorAngularExample/.gitignore b/CustomParameterEditorAngularExample/.gitignore deleted file mode 100644 index 44b8bcf..0000000 --- a/CustomParameterEditorAngularExample/.gitignore +++ /dev/null @@ -1,233 +0,0 @@ -/Properties/launchSettings.json - -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -build/ -bld/ -bin/ -Bin/ -obj/ -Obj/ - -# Visual Studio 2015 cache/options directory -.vs/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory -AppPackages/ -BundleArtifacts/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -orleans.codegen.cs - -/node_modules - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe - -# FAKE - F# Make -.fake/ diff --git a/CustomParameterEditorAngularExample/ClientApp/.gitignore b/CustomParameterEditorAngularExample/ClientApp/.gitignore deleted file mode 100644 index b61911f..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/.gitignore +++ /dev/null @@ -1,43 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. - -# compiled output -/dist -/dist-server -/tmp -/out-tsc - -# dependencies -/node_modules - -# IDEs and editors -/.idea -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# IDE - VSCode -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -# misc -/.sass-cache -/connect.lock -/coverage -/libpeerconnection.log -npm-debug.log -testem.log -/typings - -# e2e -/e2e/*.js -/e2e/*.map - -# System Files -.DS_Store -Thumbs.db diff --git a/CustomParameterEditorAngularExample/ClientApp/angular.json b/CustomParameterEditorAngularExample/ClientApp/angular.json deleted file mode 100644 index e2bf4d7..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/angular.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "CustomParameterEditorAngularExample": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "prefix": "app", - "schematics": {}, - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "progress": true, - "outputPath": "dist", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": [ - "zone.js" - ], - "tsConfig": "src/tsconfig.app.json", - "styles": [ - "node_modules/bootstrap/dist/css/bootstrap.min.css", - "src/styles.css" - ], - "assets": [ - { - "glob": "**/worker-json.js", - "input": "../node_modules/ace-builds/src-min-noconflict/", - "output": "./" - } - ], - "scripts": [] - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "aot": true, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "CustomParameterEditorAngularExample:build" - }, - "configurations": { - "production": { - "browserTarget": "CustomParameterEditorAngularExample:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "CustomParameterEditorAngularExample:build" - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ "src/tsconfig.app.json", "src/tsconfig.spec.json" ], - "exclude": [ "**/node_modules/**" ] - } - }, - "server": { - "builder": "@angular-devkit/build-angular:server", - "options": { - "outputPath": "dist-server", - "main": "src/main.ts", - "tsConfig": "src/tsconfig.server.json" - }, - "configurations": { - "dev": { - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": true - }, - "production": { - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false - } - } - } - } - } - }, - "defaultProject": "CustomParameterEditorAngularExample" -} \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/ClientApp/package.json b/CustomParameterEditorAngularExample/ClientApp/package.json deleted file mode 100644 index 84631a9..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "CustomParameterEditorAngularExample", - "version": "0.0.0", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "node --max_old_space_size=8192 ./node_modules/@angular/cli/bin/ng build", - "build:ssr": "npm run build -- --app=ssr --output-hashing=media", - "lint": "ng lint" - }, - "private": true, - "dependencies": { - "@angular/animations": "^17.0.0", - "@angular/common": "^17.0.0", - "@angular/compiler": "^17.0.0", - "@angular/core": "^17.0.0", - "@angular/forms": "^17.0.0", - "@angular/platform-browser": "^17.0.0", - "@angular/platform-browser-dynamic": "^17.0.0", - "@angular/platform-server": "^17.0.0", - "@angular/router": "^17.0.0", - "@devexpress/analytics-core": "24.1-stable", - "bootstrap": "^4.3.1", - "core-js": "^2.6.5", - "devexpress-reporting-angular": "24.1-stable", - "devextreme": "24.1-stable", - "devextreme-angular": "24.1-stable", - "rxjs": "~7.8.0", - "tslib": "^2.3.0", - "zone.js": "~0.14.2" - }, - "devDependencies": { - "@angular-devkit/build-angular": "^17.0.0", - "@angular/cli": "^17.0.0", - "@angular/compiler-cli": "^17.0.0", - "@angular/language-service": "^17.0.0", - "@types/jasmine": "~5.1.0", - "@types/node": "^18.11.9", - "jasmine-core": "~5.1.0", - "karma": "~6.4.0", - "karma-chrome-launcher": "~3.2.0", - "karma-coverage": "~2.2.0", - "karma-jasmine": "~5.1.0", - "karma-jasmine-html-reporter": "~2.1.0", - "typescript": "~5.2.2" - } -} \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/app.component.html b/CustomParameterEditorAngularExample/ClientApp/src/app/app.component.html deleted file mode 100644 index 5b6bfca..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/app.component.html +++ /dev/null @@ -1,7 +0,0 @@ - -
- -
- - - \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/app.component.ts b/CustomParameterEditorAngularExample/ClientApp/src/app/app.component.ts deleted file mode 100644 index dcb3952..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/app.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { AfterViewInit, Component, TemplateRef, ViewChild } from '@angular/core'; -import { TemplateEngine } from 'devexpress-reporting-angular/dx-report-viewer'; - -@Component({ - selector: 'app-root', - templateUrl: './app.component.html' -}) -export class AppComponent implements AfterViewInit { - title = 'report-viewer-app'; - @ViewChild('myCustomInput') myCustomInput!: TemplateRef<{ data: any }>; - constructor(private _templateEngine: TemplateEngine) { - } - ngAfterViewInit(): void { - this._templateEngine.register('custom-parameter-text-editor', this.myCustomInput); - } -} \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/app.module.ts b/CustomParameterEditorAngularExample/ClientApp/src/app/app.module.ts deleted file mode 100644 index 5390285..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/app.module.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { HttpClientModule } from '@angular/common/http'; -import { RouterModule } from '@angular/router'; - -import { AppComponent } from './app.component'; -import { NavMenuComponent } from './navmenu/nav-menu.component'; -import { HomeComponent } from './home/home.component'; -import { DxReportViewerModule, DxReportDesignerModule } from 'devexpress-reporting-angular'; -import { ReportViewerComponent } from './reportviewer/report-viewer'; - -import { DxTextBoxModule } from "devextreme-angular"; -import { DxValidatorModule } from "devextreme-angular"; - -import { CustomInputComponent } from './custominputcomponent/custom.input.component'; - -@NgModule({ - declarations: [ - AppComponent, - NavMenuComponent, - HomeComponent, - ReportViewerComponent, - CustomInputComponent, - ], - imports: [ - BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }), - HttpClientModule, - FormsModule, - DxReportViewerModule, - RouterModule.forRoot([ - { path: '', component: HomeComponent, pathMatch: 'full' }, - { path: 'DocumentViewer', component: ReportViewerComponent } - ]), - DxTextBoxModule, - DxValidatorModule - ], - providers: [], - bootstrap: [AppComponent] -}) -export class AppModule { } \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/app.server.module.ts b/CustomParameterEditorAngularExample/ClientApp/src/app/app.server.module.ts deleted file mode 100644 index d35ef5a..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/app.server.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { NgModule } from '@angular/core'; -import { ServerModule } from '@angular/platform-server'; -import { AppComponent } from './app.component'; -import { AppModule } from './app.module'; - -@NgModule({ - imports: [AppModule, ServerModule], - bootstrap: [AppComponent] -}) -export class AppServerModule { } diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/custominputcomponent/custom.input.component.html b/CustomParameterEditorAngularExample/ClientApp/src/app/custominputcomponent/custom.input.component.html deleted file mode 100644 index 0505eca..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/custominputcomponent/custom.input.component.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/custominputcomponent/custom.input.component.ts b/CustomParameterEditorAngularExample/ClientApp/src/app/custominputcomponent/custom.input.component.ts deleted file mode 100644 index eaa7d69..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/custominputcomponent/custom.input.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { IEditorViewModel } from '@devexpress/analytics-core/analytics-widgets-native'; - -@Component({ - selector: 'custom-input-component', - templateUrl: 'custom.input.component.html' -}) -export class CustomInputComponent { - @Input('data') data!: IEditorViewModel; -} diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/home/home.component.html b/CustomParameterEditorAngularExample/ClientApp/src/app/home/home.component.html deleted file mode 100644 index 5b16d8f..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/home/home.component.html +++ /dev/null @@ -1,30 +0,0 @@ -

ASP.NET Core Reporting Application

-

Welcome to your new single-page application, built with:

- -

Application uses

-
    -
  • Reporting Client-Side Widgets
  • -
  • ASP.NET Core MVC Reporting Controllers
  • -
-

Overview

- \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/home/home.component.ts b/CustomParameterEditorAngularExample/ClientApp/src/app/home/home.component.ts deleted file mode 100644 index e5d496a..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/home/home.component.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-home', - templateUrl: './home.component.html', -}) -export class HomeComponent { -} diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/navmenu/nav-menu.component.html b/CustomParameterEditorAngularExample/ClientApp/src/app/navmenu/nav-menu.component.html deleted file mode 100644 index 71805ab..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/navmenu/nav-menu.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
- -
\ No newline at end of file diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/navmenu/nav-menu.component.ts b/CustomParameterEditorAngularExample/ClientApp/src/app/navmenu/nav-menu.component.ts deleted file mode 100644 index 0d68605..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/navmenu/nav-menu.component.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-nav-menu', - templateUrl: './nav-menu.component.html', - styleUrls: ['./nav-menu.component.css'] -}) -export class NavMenuComponent { - isExpanded = false; - - collapse() { - this.isExpanded = false; - } - - toggle() { - this.isExpanded = !this.isExpanded; - } -} diff --git a/CustomParameterEditorAngularExample/ClientApp/src/app/reportviewer/report-viewer.ts b/CustomParameterEditorAngularExample/ClientApp/src/app/reportviewer/report-viewer.ts deleted file mode 100644 index fe23be3..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/app/reportviewer/report-viewer.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Component, Inject, ViewEncapsulation } from '@angular/core'; - -@Component({ - selector: 'report-viewer', - encapsulation: ViewEncapsulation.None, - templateUrl: './report-viewer.html', - styleUrls: [ - "../../../node_modules/devextreme/dist/css/dx.material.blue.light.css", - "../../../node_modules/@devexpress/analytics-core/dist/css/dx-analytics.common.css", - "../../../node_modules/@devexpress/analytics-core/dist/css/dx-analytics.material.blue.light.css", - "../../../node_modules/devexpress-reporting/dist/css/dx-webdocumentviewer.css" - ] -}) -export class ReportViewerComponent { - reportUrl: string = "CustomParameterReport"; - invokeAction: string = '/DXXRDV'; - - onCustomizeParameterEditors(event): void { - const parameter = event.args.parameter; - const info = event.args.info; - if (parameter.type === 'CustomParameterType') { - info.validationRules = info.validationRules || []; - info.validationRules.push( - { type: 'email', message: 'Email parameter value has invalid format.' }); - info.editor.header = "custom-parameter-text-editor"; - } - } - - constructor(@Inject('BASE_URL') public hostUrl: string) { } -} \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/ClientApp/src/environments/environment.prod.ts b/CustomParameterEditorAngularExample/ClientApp/src/environments/environment.prod.ts deleted file mode 100644 index 0783a04..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/environments/environment.prod.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const environment = { - production: true -}; diff --git a/CustomParameterEditorAngularExample/ClientApp/src/environments/environment.ts b/CustomParameterEditorAngularExample/ClientApp/src/environments/environment.ts deleted file mode 100644 index e604c3c..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/environments/environment.ts +++ /dev/null @@ -1,15 +0,0 @@ -// This file can be replaced during build by using the `fileReplacements` array. -// `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`. -// The list of file replacements can be found in `angular.json`. - -export const environment = { - production: false -}; - -/* - * In development mode, to ignore zone related error stack frames such as - * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can - * import the following file, but please comment it out in production mode - * because it will have performance impact when throw error - */ -// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/CustomParameterEditorAngularExample/ClientApp/src/main.ts b/CustomParameterEditorAngularExample/ClientApp/src/main.ts deleted file mode 100644 index 06df183..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/main.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - -import { AppModule } from './app/app.module'; -import { environment } from './environments/environment'; - -export function getBaseUrl() { - return document.getElementsByTagName('base')[0].href; -} - -const providers = [ - { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] } -]; - -if (environment.production) { - enableProdMode(); -} - -platformBrowserDynamic(providers).bootstrapModule(AppModule) - .catch(err => console.log(err)); diff --git a/CustomParameterEditorAngularExample/ClientApp/src/polyfills.ts b/CustomParameterEditorAngularExample/ClientApp/src/polyfills.ts deleted file mode 100644 index 4d01f43..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/polyfills.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * This file includes polyfills needed by Angular and is loaded before the app. - * You can add your own extra polyfills to this file. - * - * This file is divided into 2 sections: - * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. - * 2. Application imports. Files imported after ZoneJS that should be loaded before your main - * file. - * - * The current setup is for so-called "evergreen" browsers; the last versions of browsers that - * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), - * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. - * - * Learn more in https://angular.io/guide/browser-support - */ - -/*************************************************************************************************** - * BROWSER POLYFILLS - */ - -/** IE10 and IE11 requires the following for NgClass support on SVG elements */ -// import 'classlist.js'; // Run `npm install --save classlist.js`. - -/** - * Web Animations `@angular/platform-browser/animations` - * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. - * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). - */ -// import 'web-animations-js'; // Run `npm install --save web-animations-js`. - -/** - * By default, zone.js will patch all possible macroTask and DomEvents - * user can disable parts of macroTask/DomEvents patch by setting following flags - * because those flags need to be set before `zone.js` being loaded, and webpack - * will put import in the top of bundle, so user need to create a separate file - * in this directory (for example: zone-flags.ts), and put the following flags - * into that file, and then add the following code before importing zone.js. - * import './zone-flags.ts'; - * - * The flags allowed in zone-flags.ts are listed here. - * - * The following flags will work for all browsers. - * - * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame - * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick - * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames - * - * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js - * with the following flag, it will bypass `zone.js` patch for IE/Edge - * - * (window as any).__Zone_enable_cross_context_check = true; - * - */ - -/*************************************************************************************************** - * Zone JS is required by default for Angular itself. - */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ diff --git a/CustomParameterEditorAngularExample/ClientApp/src/tsconfig.app.json b/CustomParameterEditorAngularExample/ClientApp/src/tsconfig.app.json deleted file mode 100644 index baa77c6..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/tsconfig.app.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "outDir": "../out-tsc/app", - "baseUrl": "./", - "module": "es2015", - "types": [] - } -} diff --git a/CustomParameterEditorAngularExample/ClientApp/src/typings.d.ts b/CustomParameterEditorAngularExample/ClientApp/src/typings.d.ts deleted file mode 100644 index 3afe9fa..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/src/typings.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -/* SystemJS module definition */ -declare var module: NodeModule; -interface NodeModule { - id: string; -} diff --git a/CustomParameterEditorAngularExample/ClientApp/tsconfig.json b/CustomParameterEditorAngularExample/ClientApp/tsconfig.json deleted file mode 100644 index e80103b..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compileOnSave": false, - "compilerOptions": { - "baseUrl": "./", - "module": "es2020", - "outDir": "./dist/out-tsc", - "sourceMap": true, - "declaration": false, - "moduleResolution": "node", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "target": "es2020", - "typeRoots": [ - "node_modules/@types" - ], - "lib": [ - "es2020", - "dom" - ] - } -} diff --git a/CustomParameterEditorAngularExample/ClientApp/tslint.json b/CustomParameterEditorAngularExample/ClientApp/tslint.json deleted file mode 100644 index e757600..0000000 --- a/CustomParameterEditorAngularExample/ClientApp/tslint.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "rulesDirectory": [ - "node_modules/codelyzer" - ], - "rules": { - "arrow-return-shorthand": true, - "callable-types": true, - "class-name": true, - "comment-format": [ - true, - "check-space" - ], - "curly": true, - "deprecation": { - "severity": "warn" - }, - "eofline": true, - "forin": true, - "import-blacklist": [ - true, - "rxjs/Rx" - ], - "import-spacing": true, - "indent": [ - true, - "spaces" - ], - "interface-over-type-literal": true, - "label-position": true, - "max-line-length": [ - true, - 140 - ], - "member-access": false, - "member-ordering": [ - true, - { - "order": [ - "static-field", - "instance-field", - "static-method", - "instance-method" - ] - } - ], - "no-arg": true, - "no-bitwise": true, - "no-console": [ - true, - "debug", - "info", - "time", - "timeEnd", - "trace" - ], - "no-construct": true, - "no-debugger": true, - "no-duplicate-super": true, - "no-empty": false, - "no-empty-interface": true, - "no-eval": true, - "no-inferrable-types": [ - true, - "ignore-params" - ], - "no-misused-new": true, - "no-non-null-assertion": true, - "no-shadowed-variable": true, - "no-string-literal": false, - "no-string-throw": true, - "no-switch-case-fall-through": true, - "no-trailing-whitespace": true, - "no-unnecessary-initializer": true, - "no-unused-expression": true, - "no-use-before-declare": true, - "no-var-keyword": true, - "object-literal-sort-keys": false, - "one-line": [ - true, - "check-open-brace", - "check-catch", - "check-else", - "check-whitespace" - ], - "prefer-const": true, - "quotemark": [ - true, - "single" - ], - "radix": true, - "semicolon": [ - true, - "always" - ], - "triple-equals": [ - true, - "allow-null-check" - ], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "unified-signatures": true, - "variable-name": false, - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type" - ], - "no-output-on-prefix": true, - "no-inputs-metadata-property": true, - "no-outputs-metadata-property": true, - "no-host-metadata-property": true, - "use-lifecycle-interface": true, - "no-input-rename": true, - "no-output-rename": true, - "use-pipe-transform-interface": true, - "component-class-suffix": true, - "directive-class-suffix": true - } -} diff --git a/CustomParameterEditorAngularExample/CustomParameterEditorAngularExample.csproj b/CustomParameterEditorAngularExample/CustomParameterEditorAngularExample.csproj deleted file mode 100644 index 7755549..0000000 --- a/CustomParameterEditorAngularExample/CustomParameterEditorAngularExample.csproj +++ /dev/null @@ -1,60 +0,0 @@ - - - net8.0 - true - Latest - false - ClientApp\ - $(DefaultItemExcludes);$(SpaRoot)node_modules\**;Reports\** - - false - - - - - - - - - - - - - - - - - - PreserveNewest - - - - - Always - - - - - - - - - - - - - - - - - - - - - - %(DistFiles.Identity) - PreserveNewest - - - - \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/Pages/_ViewImports.cshtml b/CustomParameterEditorAngularExample/Pages/_ViewImports.cshtml deleted file mode 100644 index 9eb7eb2..0000000 --- a/CustomParameterEditorAngularExample/Pages/_ViewImports.cshtml +++ /dev/null @@ -1,3 +0,0 @@ -@using CustomParameterEditorAngularExample -@namespace CustomParameterEditorAngularExample.Pages -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/Program.cs b/CustomParameterEditorAngularExample/Program.cs deleted file mode 100644 index a1cce86..0000000 --- a/CustomParameterEditorAngularExample/Program.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using DevExpress.AspNetCore; -using DevExpress.AspNetCore.Reporting; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.SpaServices.AngularCli; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using DevExpress.XtraReports.Web.Extensions; -using DevExpress.Security.Resources; -using Microsoft.EntityFrameworkCore; -using CustomParameterEditorAngularExample.Services; -using CustomParameterEditorAngularExample.Data; -using CustomParameterEditorAngularExample; -using DevExpress.XtraReports.Native; - -DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(CustomParameterType)); -DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(CustomParameterType[])); -SerializationService.RegisterSerializer(CustomDataSerializer.Name, new CustomDataSerializer()); - -var builder = WebApplication.CreateBuilder(args); -builder.Services.AddDevExpressControls(); -builder.Services.AddScoped(); -builder.Services.AddMvc(); -builder.Services.ConfigureReportingServices(configurator => { - if (builder.Environment.IsDevelopment()) - configurator.UseDevelopmentMode(); - - configurator.ConfigureReportDesigner(designerConfigurator => { - }); - configurator.ConfigureWebDocumentViewer(viewerConfigurator => { - viewerConfigurator.UseCachedReportSourceBuilder(); - }); - configurator.UseAsyncEngine(); -}); -builder.Services.AddSpaStaticFiles(configuration => { - configuration.RootPath = "ClientApp/dist"; -}); -builder.Services.AddDbContext(options => options.UseSqlite(builder.Configuration.GetConnectionString("ReportsDataConnectionString"))); - -var app = builder.Build(); -using (var scope = app.Services.CreateScope()) { - var db = scope.ServiceProvider.GetService(); - db.InitializeDatabase(); -} -var contentDirectoryAllowRule = DirectoryAccessRule.Allow(new DirectoryInfo(Path.Combine(app.Environment.ContentRootPath, "..", "Content")).FullName); -AccessSettings.ReportingSpecificResources.TrySetRules(contentDirectoryAllowRule, UrlAccessRule.Allow()); -if (app.Environment.IsDevelopment()) { - app.UseDeveloperExceptionPage(); -} else { - app.UseExceptionHandler("/Home/Error"); - app.UseHsts(); -} - -app.UseHttpsRedirection(); -app.UseStaticFiles(); -if (!app.Environment.IsDevelopment()) { - app.UseSpaStaticFiles(); -} -app.UseRouting(); - - -app.UseDevExpressControls(); -System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12; -app.UseEndpoints(endpoints => { - endpoints.MapControllerRoute( - name: "default", - pattern: "{controller}/{action=Index}/{id?}"); -}); - -app.UseSpa(spa => { - // To learn more about options for serving an Angular SPA from ASP.NET Core, - // see https://go.microsoft.com/fwlink/?linkid=864501 - - spa.Options.SourcePath = "ClientApp"; - - if (app.Environment.IsDevelopment()) { - spa.UseAngularCliServer(npmScript: "start"); - spa.Options.StartupTimeout = TimeSpan.FromSeconds(240); - } -}); - -app.Run(); \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/Properties/launchSettings.json b/CustomParameterEditorAngularExample/Properties/launchSettings.json deleted file mode 100644 index ac002da..0000000 --- a/CustomParameterEditorAngularExample/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "CustomParameterEditorAngularExample": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:1635;http://localhost:1636" - } - } -} \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/appsettings.Development.json b/CustomParameterEditorAngularExample/appsettings.Development.json deleted file mode 100644 index da6fb1a..0000000 --- a/CustomParameterEditorAngularExample/appsettings.Development.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - } -} diff --git a/CustomParameterEditorAngularExample/appsettings.json b/CustomParameterEditorAngularExample/appsettings.json deleted file mode 100644 index e581ddf..0000000 --- a/CustomParameterEditorAngularExample/appsettings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Warning" - } - }, - "ConnectionStrings": { - "ReportsDataConnectionString": "Filename=Data/reportsData.db" - } -} \ No newline at end of file diff --git a/CustomParameterEditorAngularExample/wwwroot/favicon.ico b/CustomParameterEditorAngularExample/wwwroot/favicon.ico deleted file mode 100644 index a3a7999..0000000 Binary files a/CustomParameterEditorAngularExample/wwwroot/favicon.ico and /dev/null differ diff --git a/Readme.md b/Readme.md index 3320c93..b72283b 100644 --- a/Readme.md +++ b/Readme.md @@ -4,24 +4,141 @@ [![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183) [![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives) -# Reporting for Angular - Use Template to Implement Custom Client-Side Parameter Editor +# Reporting for Angular - Create a Custom Editor for a Custom Parameter Type -This example shows how to use custom types for report parameters, implement serialization/deserialization logic, and create a custom parameter editor. +This example creates a custom type for report parameters, implements serialization/deserialization logic, and implements a custom parameter editor. In this example, a custom email parameter type is implemented with email validation using the DevExtreme `dxTextBox` component. ![Reporting for Angular - Custom Parameter Editor](Images/screenshot.png) +## Run the Project + +Navigate to the *CustomParameterEditor.Server* folder and use the following command to restore dependencies and run the application: + +```console +cd CustomParameterEditor.Server +dotnet run +``` + +Two command prompts appear: + +- The ASP.NET Core API project running +- The Angular CLI running the ng start command + +Open your browser and navigate to the URL specified in the command output to see the result. + +## Implementation Details + +1. Create a `CustomParameterType` class with a `Value` property. This class represents a custom parameter type that will be used in the report. + + + ```cs + using System; + + [TypeConverter(typeof(CustomParameterTypeConverter))] + public class CustomParameterType { + public string Value { get; set; } + public override string ToString() { + return Value; + } + } + ``` + + File to review: [CustomParameterType.cs](CustomParameterEditor.Server/Services/CustomParameterType.cs) + +1. Implement a `CustomParameterTypeConverter` converter to display a parameter value in a document. + + For the sample implementation, refer to the following file: [CustomParameterType.cs](CustomParameterEditor.Server/Services/CustomParameterType.cs) + +1. Implement a custom parameter serializer. A serializer is necessary to pass data from the client to the controller on the server and store the parameter value in report definition files. + + For the sample implementation, refer to the following file: [CustomDataSerializer.cs](CustomParameterEditor.Server/Services/CustomDataSerializer.cs) + +1. In the [Program.cs](CustomParameterEditor.Server/Program.cs) file, register the `CustomParameterType`, an array of `CustomParameterType`, and the `CustomDataSerializer`: + + ```cs + DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(CustomParameterType)); + DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(CustomParameterType[])); + SerializationService.RegisterSerializer(CustomDataSerializer.Name, new CustomDataSerializer()); + ``` + +1. Add a parameter of a custom type to the report. + + ```cs + //... + Parameter customMailParameter = new Parameter { + Description = "Custom Email Parameter", + Name = "customMailParameter", + ValueInfo = "SampleMail@example.com", + Type = typeof(CustomParameterType), + Visible = true + }; + this.Parameters.Add(customMailParameter); + // .... + ``` + + File to review: [CustomParameterReport.cs](CustomParameterEditor.Server/PredefinedReports/CustomParameterReport.cs) + + +1. Configure the custom parameter editor in the `CustomizeParameterEditors` callback. Specify the custom editor template name and add validation rules: + + ```typescript + onCustomizeParameterEditors(event): void { + const parameter = event.args.parameter; + const info = event.args.info; + if (parameter.type === 'CustomParameterType') { + info.validationRules = info.validationRules || []; + info.validationRules.push( + { type: 'email', message: 'Email parameter value has invalid format.' }); + info.editor.header = "custom-parameter-text-editor"; + } + } + ``` + + Files to review: + - [report-viewer.html](CustomParameterEditor.Client/src/app/reportviewer/report-viewer.html) + - [report-viewer.ts](CustomParameterEditor.Client/src/app/reportviewer/report-viewer.ts) + +1. Create a custom input component based on the DevExtreme `dxTextBox` component. + + Files to review: + - [custom-input-component.html](CustomParameterEditor.Client/src/app/custominputcomponent/custom-input-component.html) + - [custom-input-component.ts](CustomParameterEditor.Client/src/app/custominputcomponent/custom-input-component.ts) + +1. Define an `ng-template` and register it using the `TemplateEngine` service in the `ngAfterViewInit` method to make the custom editor available as `custom-parameter-text-editor`. + + **report-viewer.html:** + + ```html + + + + ``` + + **report-viewer.ts:** + + ```typescript + @ViewChild('myCustomInput') myCustomInput!: TemplateRef<{ data: any }>; + + ngAfterViewInit(): void { + this._templateEngine.register('custom-parameter-text-editor', this.myCustomInput); + } + ``` + + Files to review: + - [report-viewer.html](CustomParameterEditor.Client/src/app/reportviewer/report-viewer.html) + - [report-viewer.ts](CustomParameterEditor.Client/src/app/reportviewer/report-viewer.ts) + ## Files to Review -- [CustomParameterType.cs](CustomParameterEditorAngularExample/Services/CustomParameterType.cs) -- [CustomDataSerializer.cs](CustomParameterEditorAngularExample/Services/CustomDataSerializer.cs) -- [CustomParameterReport.cs](CustomParameterEditorAngularExample/PredefinedReports/CustomParameterReport.cs) -- [report-viewer.html](CustomParameterEditorAngularExample/ClientApp/src/app/reportviewer/report-viewer.html) -- [report-viewer.ts](CustomParameterEditorAngularExample/ClientApp/src/app/reportviewer/report-viewer.ts) -- [custom.input.component.html](CustomParameterEditorAngularExample/ClientApp/src/app/custominputcomponent/custom.input.component.html) -- [custom.input.component.ts](CustomParameterEditorAngularExample/ClientApp/src/app/custominputcomponent/custom.input.component.ts) -- [app.component.html](CustomParameterEditorAngularExample/ClientApp/src/app/app.component.html) -- [app.component.ts](CustomParameterEditorAngularExample/ClientApp/src/app/app.component.ts) -- [app.module.ts](CustomParameterEditorAngularExample/ClientApp/src/app/app.component.ts) +- [CustomParameterType.cs](CustomParameterEditor.Server/Services/CustomParameterType.cs) +- [CustomDataSerializer.cs](CustomParameterEditor.Server/Services/CustomDataSerializer.cs) +- [CustomParameterReport.cs](CustomParameterEditor.Server/PredefinedReports/CustomParameterReport.cs) +- [Program.cs](CustomParameterEditor.Server/Program.cs) +- [report-viewer.html](CustomParameterEditor.Client/src/app/reportviewer/report-viewer.html) +- [report-viewer.ts](CustomParameterEditor.Client/src/app/reportviewer/report-viewer.ts) +- [custom-input-component.html](CustomParameterEditor.Client/src/app/custominputcomponent/custom-input-component.html) +- [custom-input-component.ts](CustomParameterEditor.Client/src/app/custominputcomponent/custom-input-component.ts) + ## Documentation