@ -0,0 +1,52 @@
|
||||
import os
|
||||
import json
|
||||
from github import Github
|
||||
|
||||
def update_latest_versions():
|
||||
version = os.environ["GITHUB_REF"].split("/")[-1]
|
||||
|
||||
if "rc" not in version:
|
||||
return False
|
||||
|
||||
with open("latest-versions.json", "r") as f:
|
||||
latest_versions = json.load(f)
|
||||
|
||||
latest_versions[0]["version"] = version
|
||||
|
||||
with open("latest-versions.json", "w") as f:
|
||||
json.dump(latest_versions, f, indent=2)
|
||||
|
||||
return True
|
||||
|
||||
def create_pr():
|
||||
g = Github(os.environ["GITHUB_TOKEN"])
|
||||
repo = g.get_repo("abpframework/abp")
|
||||
|
||||
branch_name = f"update-latest-versions-{os.environ['GITHUB_REF'].split('/')[-1]}"
|
||||
base = repo.get_branch("dev")
|
||||
repo.create_git_ref(ref=f"refs/heads/{branch_name}", sha=base.commit.sha)
|
||||
|
||||
# Get the current latest-versions.json file and its sha
|
||||
contents = repo.get_contents("latest-versions.json", ref="dev")
|
||||
file_sha = contents.sha
|
||||
|
||||
# Update the file in the repo
|
||||
repo.update_file(
|
||||
path="latest-versions.json",
|
||||
message=f"Update latest-versions.json to version {os.environ['GITHUB_REF'].split('/')[-1]}",
|
||||
content=open("latest-versions.json", "r").read().encode("utf-8"),
|
||||
sha=file_sha,
|
||||
branch=branch_name,
|
||||
)
|
||||
|
||||
pr = repo.create_pull(title="Update latest-versions.json",
|
||||
body="Automated PR to update the latest-versions.json file.",
|
||||
head=branch_name, base="dev")
|
||||
|
||||
pr.create_review_request(reviewers=["ebicoglu", "gizemmutukurt", "skoc10"])
|
||||
|
||||
if __name__ == "__dev__":
|
||||
should_create_pr = update_latest_versions()
|
||||
if should_create_pr:
|
||||
create_pr()
|
||||
|
@ -0,0 +1,33 @@
|
||||
name: Update Latest Versions
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
update-versions:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install PyGithub
|
||||
|
||||
- name: Update latest-versions.json and create PR
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
python .github/scripts/update_versions.py
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 613 KiB After Width: | Height: | Size: 613 KiB |
Before Width: | Height: | Size: 523 KiB After Width: | Height: | Size: 523 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 329 KiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 234 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 150 KiB |
After Width: | Height: | Size: 48 KiB |
@ -0,0 +1,118 @@
|
||||
# 💻 How to Optimize Your ASP.NET Application for Improved Performance 🚀
|
||||
|
||||
If you want your ASP.NET application to perform well, you need to optimize it for speed, responsiveness, and user experience. Performance optimization is critical for factors like fast page load times, improved response efficiency, and happy users. In this article, I'll provide several tips and tricks to help you optimize performance in ASP.NET Core.
|
||||
|
||||
## 🚀 Use Response Compression in Your ASP.NET Application
|
||||
You can use ASP.NET Core's built-in response compression middleware to compress the response data and reduce the amount of data that needs to be transferred over the network. To use response compression, add the following code to your application's Startup.cs file:
|
||||
|
||||
```csharp
|
||||
services.AddResponseCompression(options =>
|
||||
{
|
||||
options.EnableForHttps = true;
|
||||
});
|
||||
|
||||
app.UseResponseCompression();
|
||||
```
|
||||
|
||||
## 🖼️ Optimize Images in Your ASP.NET Application:
|
||||
|
||||
Images can be a major contributor to page bloat and slow load times. Here are some tips to optimize images:
|
||||
|
||||
🖌️ Use a tool like ImageOptim or Kraken.io to compress and optimize images.
|
||||
|
||||
🖼️ Specify the width and height of images in HTML so the browser can allocate space for them before they load.
|
||||
|
||||
📝 Use alt attributes to provide descriptive text for images, which can improve accessibility and also help with SEO.
|
||||
|
||||
📜 Use lazy loading for images that are below the fold, meaning they're not visible on the initial screen view. You can use libraries like Vanilla LazyLoad to implement lazy loading.
|
||||
|
||||
📱 Use responsive images to serve different image sizes to different devices. This can improve page load times by reducing the size of images that are displayed on smaller devices.
|
||||
|
||||
💻 Example:
|
||||
|
||||
```html
|
||||
<picture>
|
||||
<source media="(min-width: 650px)" data-srcset="image.webp">
|
||||
<source media="(min-width: 465px)" data-srcset="image_small.webp">
|
||||
<img src="placeholder.png" data-src="image.webp" alt="Image" width="100" height="100" class="lazy" />
|
||||
</picture>
|
||||
```
|
||||
|
||||
```javascript
|
||||
var lazyLoadInstance = new LazyLoad();
|
||||
```
|
||||
|
||||
## 🧱 Optimize HTML in Your ASP.NET Application:
|
||||
|
||||
The structure and organization of HTML can affect the page speed. Here are some tips to optimize HTML:
|
||||
|
||||
📝 Use the heading tags (h1, h2, h3, etc.) in a logical and sequential order.
|
||||
|
||||
🔩 Use the "defer" attribute for script tags that don't need to be executed immediately. This can improve the page load times by delaying the execution of scripts until after the page has rendered.
|
||||
|
||||
🔩 Use the "async" attribute for script tags that can be executed asynchronously. This can further improve the page load times by allowing scripts to be downloaded and executed simultaneously.
|
||||
|
||||
🧱 Use semantic HTML elements (like nav, section, and article) to provide additional structure and meaning to the page.
|
||||
|
||||
## 🎨 Optimize CSS and JavaScript in Your ASP.NET Application:
|
||||
|
||||
CSS and JavaScript files can be a major contributor to the page load times. Here are some tips to optimize CSS and JavaScript in your ASP.NET application:
|
||||
|
||||
🔨 Minify and concatenate CSS and JavaScript files to reduce their size.
|
||||
|
||||
🔩 Use the "defer" or "async" attributes for script tags to delay or asynchronously load scripts.
|
||||
|
||||
## 🔡 Use system fonts in Your ASP.NET Application:
|
||||
|
||||
Loading custom fonts can be slow and increase page load times. Using system fonts can improve page speed by allowing the browser to use fonts that are already installed on the user's device.
|
||||
|
||||
## 🖼️ Use Placeholders and Progress Indicators in Your ASP.NET Application:
|
||||
|
||||
To improve the perceived performance of your website, you can use placeholders and progress indicators for slow-loading sections of your page. You can use JavaScript to load these sections after the initial page load.
|
||||
|
||||
💻 Example:
|
||||
|
||||
```html
|
||||
|
||||
<div id="placeholder" data-url="/slow-loading-content">
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
```javascript
|
||||
const placeholder = document.querySelector('#placeholder');
|
||||
fetch(placeholder.dataset.url)
|
||||
.then(response => response.text())
|
||||
.then(html => placeholder.innerHTML = html);
|
||||
```
|
||||
|
||||
## 🔗 Use the Appropriate Link Text and ARIA Labels:
|
||||
|
||||
When using links, use appropriate link texts that accurately describe the content of the linked page. This can improve the accessibility and also help with SEO.
|
||||
|
||||
ARIA labels should also be used to provide additional context for links. This can also improve the accessibility and help with SEO.
|
||||
|
||||
💻 Example:
|
||||
|
||||
```html
|
||||
<a href="https://example.com/" aria-label="Go to Example">Example</a>
|
||||
<a href="https://example.com/" aria-label="Go to Another Example">Another Example</a>
|
||||
```
|
||||
|
||||
## 🌐 Optimize the Third-party Resources in Your ASP.NET Application:
|
||||
|
||||
Third-party resources like social media widgets and advertising scripts can slow down the page load times. Here are some tips to optimize third-party resources:
|
||||
|
||||
🔩 Use asynchronous scripts when possible.
|
||||
|
||||
🔍 Only load third-party resources that are necessary for the page.
|
||||
|
||||
By following these optimization techniques, you can significantly improve the page speed of your ASP.NET Core web application.
|
||||
|
||||
## What is ABP Framework?
|
||||
|
||||
ABP Framework offers an opinionated architecture to build enterprise software solutions with ASP.NET Core best practices on top of the .NET and the ASP.NET Core platforms. It provides the fundamental web application infrastructure, production-ready dotnet startup templates, modules, asp.net core ui themes, tooling, guides and documentation to implement that ASP.NET core architecture properly and automate the details and repetitive work as much as possible.
|
||||
|
||||
If you are starting a new ASP.NET Core project, try [abp.io](https://abp.io/) now...
|
||||
|
||||
**IT IS FREE AND OPEN-SOURCE!**
|
@ -0,0 +1,325 @@
|
||||
# Convert Create/Edit Modals to Page
|
||||
|
||||
In this document we will explain how to convert the BookStore's Books create & edit modals to regular Angular component pages.
|
||||
|
||||
## Before
|
||||
|
||||

|
||||
|
||||
## After
|
||||
|
||||

|
||||
|
||||
# BooksComponent
|
||||
|
||||
This is the main component of the books management. The create & update operations are done in this page. So we'll remove the create & update operations from this page and move a separate angular component for each operation. Each component will be a page.
|
||||
|
||||
- Remove the Create & Update modal on template
|
||||
|
||||

|
||||
|
||||
- Modify the **NewBook** button with a link to the **CreateBookComponent** page.
|
||||
|
||||
```html
|
||||
<button
|
||||
*abpPermission="'BookStore.Books.Create'"
|
||||
id="create"
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
[routerLink]="['create']"
|
||||
>
|
||||
<i class="fa fa-plus me-1"></i>
|
||||
<span>{{ '::NewBook' | abpLocalization }}</span>
|
||||
</button>
|
||||
```
|
||||
|
||||
- Modify the **Edit** button with a link to the **EditBookComponent** page.
|
||||
|
||||
```html
|
||||
<button
|
||||
*abpPermission="'BookStore.Books.Edit'"
|
||||
ngbDropdownItem
|
||||
[routerLink]="['edit', row.id]"
|
||||
>
|
||||
{{ '::Edit' | abpLocalization }}
|
||||
</button>
|
||||
```
|
||||
|
||||
- Remove all unused methods and variables in the `BookComponent` except the **book** variable, the **ngOnInit** and **delete** methods.
|
||||
|
||||
|
||||

|
||||
|
||||
- Also we can clear unncessary imports
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
# CreateBookComponent Page
|
||||
|
||||
Create a new component by the name `create-book` in your project.
|
||||
```bash
|
||||
yarn ng g c book/create-book --skip-tests --style=none
|
||||
```
|
||||
|
||||
- `create-book.component.html`
|
||||
|
||||
```html
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form [formGroup]="form" (ngSubmit)="save()">
|
||||
<div class="form-group">
|
||||
<label for="author-id">Author</label><span> * </span>
|
||||
<select class="form-control" id="author-id" formControlName="authorId">
|
||||
<option [ngValue]="null">Select author</option>
|
||||
<option [ngValue]="author.id" *ngFor="let author of authors$ | async">
|
||||
{{ author.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="book-name">Name</label><span> * </span>
|
||||
<input type="text" id="book-name" class="form-control" formControlName="name" autofocus />
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="book-price">Price</label><span> * </span>
|
||||
<input type="number" id="book-price" class="form-control" formControlName="price" />
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="book-type">Type</label><span> * </span>
|
||||
<select class="form-control" id="book-type" formControlName="type">
|
||||
<option [ngValue]="null">Select a book type</option>
|
||||
<option [ngValue]="type.value" *ngFor="let type of bookTypes">
|
||||
{{ '::Enum:BookType.' + type.value | abpLocalization }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label>Publish date</label><span> * </span>
|
||||
<input
|
||||
#datepicker="ngbDatepicker"
|
||||
class="form-control"
|
||||
name="datepicker"
|
||||
formControlName="publishDate"
|
||||
ngbDatepicker
|
||||
(click)="datepicker.toggle()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="pt-2">
|
||||
<button type="button" class="btn btn-secondary m-1" [routerLink]="['/books']">
|
||||
{{ '::Cancel' | abpLocalization }}
|
||||
</button>
|
||||
|
||||
<button class="btn btn-primary">
|
||||
<i class="fa fa-check mr-1"></i>
|
||||
{{ '::Save' | abpLocalization }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
- `create-book.component.ts`
|
||||
|
||||
```ts
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { map } from 'rxjs';
|
||||
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { BookService, bookTypeOptions } from '@proxy/books';
|
||||
|
||||
const { required } = Validators;
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-book',
|
||||
templateUrl: './create-book.component.html',
|
||||
providers: [{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter }],
|
||||
})
|
||||
export class CreateBookComponent {
|
||||
//inject() function came with Angular v14, detail: https://angular.io/api/core/inject
|
||||
private readonly router = inject(Router);
|
||||
private readonly fb = inject(FormBuilder);
|
||||
private readonly bookService = inject(BookService);
|
||||
|
||||
form: FormGroup;
|
||||
authors$ = this.bookService.getAuthorLookup().pipe(map(({ items }) => items));
|
||||
bookTypes = bookTypeOptions;
|
||||
|
||||
private buildForm() {
|
||||
this.form = this.fb.group({
|
||||
authorId: [null, required],
|
||||
name: [null, required],
|
||||
type: [null, required],
|
||||
publishDate: [undefined, required],
|
||||
price: [null, required],
|
||||
});
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.buildForm();
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.form.invalid) return;
|
||||
|
||||
this.bookService.create(this.form.value).subscribe(() => {
|
||||
this.router.navigate(['/books']);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# EditBookComponent Page
|
||||
|
||||
Create a new component by the name **edit-book** in your project.
|
||||
|
||||
```bash
|
||||
yarn ng g c book/edit-book --skip-tests --style=none
|
||||
```
|
||||
|
||||
- `edit-book.component.html`
|
||||
|
||||
```html
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form *ngIf="form" [formGroup]="form" (ngSubmit)="save()">
|
||||
<div class="form-group">
|
||||
<label for="author-id">Author</label><span> * </span>
|
||||
<select class="form-control" id="author-id" formControlName="authorId">
|
||||
<option [ngValue]="null">Select author</option>
|
||||
<option [ngValue]="author.id" *ngFor="let author of authors$ | async">
|
||||
{{ author.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="book-name">Name</label><span> * </span>
|
||||
<input type="text" id="book-name" class="form-control" formControlName="name" autofocus />
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="book-price">Price</label><span> * </span>
|
||||
<input type="number" id="book-price" class="form-control" formControlName="price" />
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="book-type">Type</label><span> * </span>
|
||||
<select class="form-control" id="book-type" formControlName="type">
|
||||
<option [ngValue]="null">Select a book type</option>
|
||||
<option [ngValue]="type.value" *ngFor="let type of bookTypes">
|
||||
{{ '::Enum:BookType.' + type.value | abpLocalization }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label>Publish date</label><span> * </span>
|
||||
<input
|
||||
#datepicker="ngbDatepicker"
|
||||
class="form-control"
|
||||
name="datepicker"
|
||||
formControlName="publishDate"
|
||||
ngbDatepicker
|
||||
(click)="datepicker.toggle()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="pt-2">
|
||||
<button type="button" class="btn btn-secondary m-1" [routerLink]="['/books']">
|
||||
{{ '::Cancel' | abpLocalization }}
|
||||
</button>
|
||||
|
||||
<button class="btn btn-primary">
|
||||
<i class="fa fa-check mr-1"></i>
|
||||
{{ '::Save' | abpLocalization }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
- `edit-book.component.ts`
|
||||
|
||||
```ts
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { filter, map, switchMap, tap } from 'rxjs';
|
||||
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { BookDto, BookService, bookTypeOptions } from '@proxy/books';
|
||||
|
||||
const { required } = Validators;
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-book',
|
||||
templateUrl: './edit-book.component.html',
|
||||
providers: [{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter }],
|
||||
})
|
||||
export class EditBookComponent {
|
||||
//inject() function came with Angular v14, detail: https://angular.io/api/core/inject
|
||||
private readonly router = inject(Router);
|
||||
private readonly activatedRoute = inject(ActivatedRoute);
|
||||
private readonly fb = inject(FormBuilder);
|
||||
private readonly bookService = inject(BookService);
|
||||
|
||||
id: string;
|
||||
form: FormGroup;
|
||||
authors$ = this.bookService.getAuthorLookup().pipe(map(({ items }) => items));
|
||||
bookTypes = bookTypeOptions;
|
||||
|
||||
private buildForm(book: BookDto): void {
|
||||
this.form = this.fb.group({
|
||||
authorId: [book.authorId, required],
|
||||
name: [book.name, required],
|
||||
type: [book.type, required],
|
||||
publishDate: [new Date(book.publishDate), required],
|
||||
price: [book.price, required],
|
||||
});
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.activatedRoute.params
|
||||
.pipe(
|
||||
filter(params => params.id),
|
||||
tap(({ id }) => (this.id = id)),
|
||||
switchMap(({ id }) => this.bookService.get(id)),
|
||||
tap(book => this.buildForm(book))
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
save(): void {
|
||||
if (this.form.invalid) return;
|
||||
|
||||
this.bookService.update(this.id, this.form.value).subscribe(() => {
|
||||
this.router.navigate(['/books']);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Update BookRoutingModule
|
||||
Finally add 2 items to the routes array in the `book-routing.module.ts`
|
||||
```ts
|
||||
import { CreateBookComponent } from './create-book/create-book.component';
|
||||
import { EditBookComponent } from './edit-book/edit-book.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', component: BookComponent, canActivate: [AuthGuard, PermissionGuard] },
|
||||
{ path: 'create', component: CreateBookComponent },
|
||||
{ path: 'edit/:id', component: EditBookComponent },
|
||||
];
|
||||
```
|
||||
|
||||
|
||||
You can check the following commit for more details: https://github.com/abpframework/abp-samples/commit/351ad5e093036702edbb15169968935496afea0e
|
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 129 KiB |
After Width: | Height: | Size: 291 KiB |
After Width: | Height: | Size: 678 KiB |
@ -0,0 +1,45 @@
|
||||
# Security Headers
|
||||
|
||||
ABP Framework allows you to add frequently used security headers into your application. The following security headers will be added as response headers to your application if you use the `UseAbpSecurityHeaders` middleware:
|
||||
|
||||
* `X-Content-Type-Options`: Tells the browser to not try and guess what a mime-type of a resource might be, and to just take what mime-type the server has returned.
|
||||
* `X-XSS-Protection`: This is a feature of Internet Explorer, Chrome, and Safari that stops pages from loading when they detect reflected cross-site scripting (XSS) attacks.
|
||||
* `X-Frame-Options`: This header can be used to indicate whether or not a browser should be allowed to render a page in a `<iframe>` tag. By specifying this header value as *SAMEORIGIN*, you can make it displayed in a frame on the same origin as the page itself.
|
||||
* `Content-Security-Policy`: This response header allows you to restrict which resources (such as JavaScript, CSS, images, manifests, etc.) can be loaded, and the URLs that they can be loaded from. This security header will only be added if you configure the `AbpSecurityHeadersOptions` class and enable it.
|
||||
|
||||
## Configuration
|
||||
|
||||
### AbpSecurityHeadersOptions
|
||||
|
||||
`AbpSecurityHeadersOptions` is the main class to enable the `Content-Security-Policy` header, define its value and set other security headers that you want to add to your application.
|
||||
|
||||
**Example:**
|
||||
|
||||
```csharp
|
||||
Configure<AbpSecurityHeadersOptions>(options =>
|
||||
{
|
||||
options.UseContentSecurityPolicyHeader = true; //false by default
|
||||
options.ContentSecurityPolicyValue = "object-src 'none'; form-action 'self'; frame-ancestors 'none'";
|
||||
|
||||
//adding additional security headers
|
||||
options.Headers["Referrer-Policy"] = "no-referrer";
|
||||
});
|
||||
```
|
||||
|
||||
> If the header is the same, the additional security headers you defined take precedence over the default security headers. In other words, it overrides the default security headers' values.
|
||||
|
||||
## Security Headers Middleware
|
||||
|
||||
Security Headers middleware is an ASP.NET Core request pipeline [middleware](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware) that adds pre-defined security headers to your application, including `X-Content-Type-Options`, `X-XSS-Protection`, and `X-Frame-Options`. Additionally, this middleware also includes those unique security headers in your application if you configure the `AbpSecurityHeadersOptions` as mentioned above.
|
||||
|
||||
**Example:**
|
||||
|
||||
```csharp
|
||||
app.UseAbpSecurityHeaders();
|
||||
```
|
||||
|
||||
> You can add this middleware into the `OnApplicationInitialization` method of your module class to register it to the request pipeline. This middleware is already configured in the [ABP Commercial Startup Templates](https://docs.abp.io/en/commercial/latest/startup-templates/index), so you don't need to manually add it if you are using one of these startup templates.
|
||||
|
||||
After that, you have registered the `UseAbpSecurityHeaders` middleware into the request pipeline, the defined security headers will be shown in the response headers as in the figure below:
|
||||
|
||||

|
After Width: | Height: | Size: 12 KiB |
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Volo.Abp.Cli.ProjectBuilding.Building;
|
||||
|
||||
namespace Volo.Abp.Cli.ProjectBuilding.Templates;
|
||||
|
||||
public class RandomizeAuthServerPassPhraseStep : ProjectBuildPipelineStep
|
||||
{
|
||||
protected const string DefaultPassPhrase = "00000000-0000-0000-0000-000000000000";
|
||||
|
||||
public override void Execute(ProjectBuildContext context)
|
||||
{
|
||||
var files = context.Files
|
||||
.Where(x => !x.IsDirectory)
|
||||
.Where(x => x.Content.IndexOf(DefaultPassPhrase, StringComparison.InvariantCultureIgnoreCase) >= 0)
|
||||
.ToList();
|
||||
|
||||
var randomPassPhrase = Guid.NewGuid().ToString("D");
|
||||
foreach (var file in files)
|
||||
{
|
||||
file.NormalizeLineEndings();
|
||||
|
||||
var lines = file.GetLines();
|
||||
for (var i = 0; i < lines.Length; i++)
|
||||
{
|
||||
if (lines[i].Contains(DefaultPassPhrase))
|
||||
{
|
||||
lines[i] = lines[i].Replace(DefaultPassPhrase, randomPassPhrase);
|
||||
}
|
||||
}
|
||||
|
||||
file.SetLines(lines);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,790 @@
|
||||
@page
|
||||
@model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.DatePickerModel
|
||||
|
||||
@section styles {
|
||||
<abp-style-bundle>
|
||||
<abp-style src="/css/demo.css"/>
|
||||
</abp-style-bundle>
|
||||
}
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/default.min.css">
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad();</script>
|
||||
|
||||
<h2>Date Picker & Date Range Picker</h2>
|
||||
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
<abp-date-picker placeholder="New" single-open-and-clear-button="false" week-numbers="Iso" time-picker="true" required today-button-classes="btn-primary" picker-id="testPicker" asp-for="DateTime"></abp-date-picker>
|
||||
</div>
|
||||
<div class="code-area" id="test-picker">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Modal Class">
|
||||
<pre><code>
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public DateTime DateTime { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
DateTime = DateTime == default ? DateTime.Now : DateTime;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Tag Helper" active="true">
|
||||
<pre><code>
|
||||
<abp-date-picker placeholder="New" single-open-and-clear-button="false" week-numbers="Iso" time-picker="true" required today-button-classes="btn-primary" picker-id="testPicker" asp-for="DateTime"/>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DateTime">DateTime</label><span> * </span>
|
||||
<abp-date-picker placeholder="New" required="" data-show-i-s-o-week-numbers="true" data-time-picker="true" data-today-button-classes="btn-primary" id="testPicker" data-single-open-and-clear-button="false" data-date="2023-04-12T17:56:33.1115260+03:00">
|
||||
<div class="input-group">
|
||||
<input placeholder="New" required="" type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="clear" class="btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DateTime" data-valmsg-replace="true"></span><input data-date="true" type="hidden" data-val="true" data-val-required="The DateTime field is required." id="DateTime" name="DateTime" value="Wed Apr 12 2023 17:56:33 GMT+0300">
|
||||
</abp-date-picker>
|
||||
</div>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
@section scripts {
|
||||
<script>
|
||||
var newPicker = abp.libs.bootstrapDateRangePicker.createDateRangePicker(
|
||||
{
|
||||
label: "New JavaScript Picker",
|
||||
startDate: "2020-01-01",
|
||||
endDate: "2020-01-02",
|
||||
singleOpenAndClearButton: false,
|
||||
placeholder: "New Picker",
|
||||
});
|
||||
newPicker.insertAfter($('#test-picker').parent());
|
||||
</script>
|
||||
}
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Javascript" active="true">
|
||||
<pre><code>
|
||||
var newPicker = abp.libs.bootstrapDateRangePicker.createDateRangePicker(
|
||||
{
|
||||
label: "New JavaScript Picker",
|
||||
startDate: "2020-01-01",
|
||||
endDate: "2020-01-02",
|
||||
singleOpenAndClearButton: false,
|
||||
placeholder: "New Picker",
|
||||
});
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">New JavaScript Picker</label>
|
||||
<abp-date-range-picker>
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control" placeholder="New Picker">
|
||||
<button type="button" class="btn btn-outline-secondary" tabindex="-1" data-type="open">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" tabindex="-1" data-type="clear">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
</abp-date-range-picker>
|
||||
</div>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
<abp-date-range-picker time-picker="true" asp-for-end="EndDate" asp-for-start="StartDate"></abp-date-range-picker>
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Modal Class">
|
||||
<pre><code>
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
EndDate = EndDate == default ? DateTime.Now : EndDate;
|
||||
DateTime = DateTime == default ? DateTime.Now : DateTime;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Tag Helper" active="true">
|
||||
<pre><code>
|
||||
<abp-date-range-picker time-picker="true" asp-for-end="EndDate" asp-for-start="StartDate"/>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="StartDate">StartDate</label>
|
||||
<abp-date-range-picker data-time-picker="true" data-start-date="0001-01-01T00:00:00.0000000" data-end-date="2023-04-12T18:02:13.2033440+03:00">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="StartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="EndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" data-val="true" data-val-required="The StartDate field is required." id="StartDate" name="StartDate" value="Mon Jan 01 0001 00:00:00 GMT+0155"><input data-end-date="true" type="hidden" data-val="true" data-val-required="The EndDate field is required." id="EndDate" name="EndDate" value="Wed Apr 12 2023 18:02:13 GMT+0300">
|
||||
</abp-date-range-picker>
|
||||
</div>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="NullableDateTime"></abp-date-picker>
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Modal Class">
|
||||
<pre><code>
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public DateTime? NullableDateTime { get; set; }
|
||||
}
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Tag Helper" active="true">
|
||||
<pre><code>
|
||||
<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="NullableDateTime"/>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="NullableDateTime">NullableDateTime</label>
|
||||
<abp-date-picker data-today-button-classes="btn-primary" data-auto-update-input="true">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary d-none" data-busy-text="Processing...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="clear" class="btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableDateTime" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="NullableDateTime" name="NullableDateTime" value="2023-04-12">
|
||||
</abp-date-picker>
|
||||
</div>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
<abp-date-range-picker clear-button="false" asp-for-end="NullableEndDate" asp-for-start="NullableStartDate"></abp-date-range-picker>
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Modal Class">
|
||||
<pre><code>
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public DateTime? NullableStartDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTime? NullableEndDate { get; set; }
|
||||
}
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Tag Helper" active="true">
|
||||
<pre><code>
|
||||
<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="NullableDateTime"/>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="NullableStartDate">NullableStartDate</label>
|
||||
<abp-date-range-picker>
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableStartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableEndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="NullableStartDate" name="NullableStartDate" value=""><input data-end-date="true" type="hidden" id="NullableEndDate" name="NullableEndDate" value="">
|
||||
</abp-date-range-picker>
|
||||
</div>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="DateTimeDateTimeOffset"></abp-date-picker>
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Modal Class">
|
||||
<pre><code>
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public DateTimeOffset DateTimeDateTimeOffset { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
DateTimeDateTimeOffset = DateTimeDateTimeOffset == default ? DateTimeOffset.Now : DateTimeDateTimeOffset;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Tag Helper" active="true">
|
||||
<pre><code>
|
||||
<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="DateTimeDateTimeOffset"/>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DateTimeDateTimeOffset">DateTimeDateTimeOffset</label>
|
||||
<abp-date-picker data-today-button-classes="btn-primary" data-auto-update-input="true" data-date="2023-04-12T18:10:05.6171150+03:00">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary d-none" data-busy-text="Processing...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="clear" class="btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DateTimeDateTimeOffset" data-valmsg-replace="true"></span><input data-date="true" type="hidden" data-val="true" data-val-required="The DateTimeDateTimeOffset field is required." id="DateTimeDateTimeOffset" name="DateTimeDateTimeOffset" value="2023-04-12">
|
||||
</abp-date-picker>
|
||||
</div>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
<abp-date-range-picker clear-button="false" asp-for-end="EndDateTimeOffset" asp-for-start="StartDateTimeOffset"></abp-date-range-picker>
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Modal Class">
|
||||
<pre><code>
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public DateTimeOffset StartDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTimeOffset EndDateTimeOffset { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
StartDateTimeOffset = StartDateTimeOffset == default ? DateTimeOffset.Now : StartDateTimeOffset;
|
||||
EndDateTimeOffset = EndDateTimeOffset == default ? DateTimeOffset.Now : EndDateTimeOffset;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Tag Helper" active="true">
|
||||
<pre><code>
|
||||
<abp-date-range-picker clear-button="false" asp-for-end="EndDateTimeOffset" asp-for-start="StartDateTimeOffset"/>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="StartDateTimeOffset">StartDateTimeOffset</label>
|
||||
<abp-date-range-picker data-start-date="2023-04-12T18:11:50.9560980+03:00" data-end-date="2023-04-12T18:11:50.9560980+03:00">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="StartDateTimeOffset" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="EndDateTimeOffset" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" data-val="true" data-val-required="The StartDateTimeOffset field is required." id="StartDateTimeOffset" name="StartDateTimeOffset" value="Wed Apr 12 2023 18:11:50 GMT+0300"><input data-end-date="true" type="hidden" data-val="true" data-val-required="The EndDateTimeOffset field is required." id="EndDateTimeOffset" name="EndDateTimeOffset" value="Wed Apr 12 2023 18:11:50 GMT+0300">
|
||||
</abp-date-range-picker>
|
||||
</div>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="NullableDateTimeDateTimeOffset"></abp-date-picker>
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Modal Class">
|
||||
<pre><code>
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public DateTimeOffset DateTimeDateTimeOffset { get; set; }
|
||||
}
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Tag Helper" active="true">
|
||||
<pre><code>
|
||||
<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="NullableDateTimeDateTimeOffset"/>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="NullableDateTimeDateTimeOffset">NullableDateTimeDateTimeOffset</label>
|
||||
<abp-date-picker data-today-button-classes="btn-primary" data-auto-update-input="true">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary d-none" data-busy-text="Processing...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="clear" class="btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableDateTimeDateTimeOffset" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="NullableDateTimeDateTimeOffset" name="NullableDateTimeDateTimeOffset" value="2023-04-12">
|
||||
</abp-date-picker>
|
||||
</div>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
<abp-date-range-picker clear-button="false" asp-for-end="NullableEndDateTimeOffset" asp-for-start="NullableStartDateTimeOffset"></abp-date-range-picker>
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Modal Class">
|
||||
<pre><code>
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public DateTimeOffset? NullableStartDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTimeOffset? NullableEndDateTimeOffset { get; set; }
|
||||
}
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Tag Helper" active="true">
|
||||
<pre><code>
|
||||
<abp-date-range-picker clear-button="false" asp-for-end="NullableEndDateTimeOffset" asp-for-start="NullableStartDateTimeOffset"/>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="NullableStartDateTimeOffset">NullableStartDateTimeOffset</label>
|
||||
<abp-date-range-picker>
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableStartDateTimeOffset" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableEndDateTimeOffset" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="NullableStartDateTimeOffset" name="NullableStartDateTimeOffset" value=""><input data-end-date="true" type="hidden" id="NullableEndDateTimeOffset" name="NullableEndDateTimeOffset" value="">
|
||||
</abp-date-range-picker>
|
||||
</div>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="StringDate"></abp-date-picker>
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Modal Class">
|
||||
<pre><code>
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public string StringDate { get; set; }
|
||||
}
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Tag Helper" active="true">
|
||||
<pre><code>
|
||||
<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="StringDate"/>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="StringDate">StringDate</label>
|
||||
<abp-date-picker data-today-button-classes="btn-primary" data-auto-update-input="true">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary d-none" data-busy-text="Processing...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="clear" class="btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="StringDate" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="StringDate" name="StringDate" value="2023-04-12">
|
||||
</abp-date-picker>
|
||||
</div>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
<abp-date-range-picker clear-button="false" asp-for-end="StringEndDate" asp-for-start="StringStartDate"></abp-date-range-picker>
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Modal Class">
|
||||
<pre><code>
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public string StringStartDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string StringEndDate { get; set; }
|
||||
}
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Tag Helper" active="true">
|
||||
<pre><code>
|
||||
<abp-date-range-picker clear-button="false" asp-for-end="StringEndDate" asp-for-start="StringStartDate"></abp-date-range-picker>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="StringStartDate">StringStartDate</label>
|
||||
<abp-date-range-picker>
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="StringStartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="StringEndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="StringStartDate" name="StringStartDate" value=""><input data-end-date="true" type="hidden" id="StringEndDate" name="StringEndDate" value="">
|
||||
</abp-date-range-picker>
|
||||
</div>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Dynamic Form</h2>
|
||||
|
||||
|
||||
<div class="demo-with-code">
|
||||
<div class="demo-area">
|
||||
<abp-dynamic-form abp-model="DynamicFormExample">
|
||||
</abp-dynamic-form>
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<abp-tabs>
|
||||
<abp-tab title="Modal Class">
|
||||
<pre><code>
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
public class DynamicForm
|
||||
{
|
||||
[BindProperty]
|
||||
[DateRangePicker("MyPicker",true)]
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DateRangePicker("MyPicker",false)]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
public DateTime DateTime { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker2",true)]
|
||||
public DateTime? NullableStartDate { get; set; }
|
||||
[BindProperty]
|
||||
[DateRangePicker("MyPicker2")]
|
||||
public DateTime? NullableEndDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
public DateTime? NullableDateTime { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker3",true)]
|
||||
public DateTimeOffset StartDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker3")]
|
||||
public DateTimeOffset EndDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
public DateTimeOffset DateTimeDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker4",true)]
|
||||
public DateTimeOffset? NullableStartDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker4")]
|
||||
public DateTimeOffset? NullableEndDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
public DateTimeOffset? NullableDateTimeDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker5",true)]
|
||||
public string StringStartDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker5")]
|
||||
public string StringEndDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DatePicker]
|
||||
public string StringDate { get; set; }
|
||||
}
|
||||
|
||||
public AbpDatePickerOptions DatePickerOptions { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DynamicForm DynamicFormExample { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
DynamicFormExample ??= new DynamicForm
|
||||
{
|
||||
StartDate = DateTime.Now,
|
||||
EndDate = DateTime.Now,
|
||||
DateTime = DateTime.Now,
|
||||
|
||||
StartDateTimeOffset = DateTimeOffset.Now,
|
||||
EndDateTimeOffset = DateTimeOffset.Now,
|
||||
DateTimeDateTimeOffset = DateTimeOffset.Now,
|
||||
};
|
||||
|
||||
DatePickerOptions = new AbpDatePickerOptions();
|
||||
DatePickerOptions.LinkedCalendars = false;
|
||||
DatePickerOptions.Ranges = new List<AbpDatePickerRange>();
|
||||
DatePickerOptions.Ranges.Add(new AbpDatePickerRange("Today", DateTime.Now, DateTime.Now));
|
||||
}
|
||||
|
||||
public void OnPost()
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Tag Helper" active="true">
|
||||
<pre><code>
|
||||
<abp-dynamic-form abp-model="DynamicFormExample">
|
||||
</abp-dynamic-form>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
<abp-tab title="Rendered">
|
||||
<pre><code>
|
||||
<form method="post" novalidate="novalidate">
|
||||
<div class="row">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DynamicFormExample_StartDate">Start Date - End Date</label>
|
||||
<abp-date-range-picker id="MyPicker" data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}" data-start-date="2023-04-17T15:21:46.6569460+03:00" data-end-date="2023-04-17T15:21:46.6570750+03:00">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<ti class="fa fa-times"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.StartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.EndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" data-val="true" data-val-required="The Start Date - End Date field is required." id="DynamicFormExample_StartDate" name="DynamicFormExample.StartDate" value="Mon Apr 17 2023 15:21:46 GMT+0300"><input data-end-date="true" type="hidden" data-val="true" data-val-required="The EndDate field is required." id="DynamicFormExample_EndDate" name="DynamicFormExample.EndDate" value="Mon Apr 17 2023 15:21:46 GMT+0300">
|
||||
</abp-date-range-picker>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DynamicFormExample_NullableStartDate">Nullable Start Date - Nullable End Date</label>
|
||||
<abp-date-range-picker id="MyPicker2" data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableStartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableEndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="DynamicFormExample_NullableStartDate" name="DynamicFormExample.NullableStartDate" value=""><input data-end-date="true" type="hidden" id="DynamicFormExample_NullableEndDate" name="DynamicFormExample.NullableEndDate" value="">
|
||||
</abp-date-range-picker>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DynamicFormExample_StartDateTimeOffset">Start DateTime Offset - End DateTime Offset</label>
|
||||
<abp-date-range-picker id="MyPicker3" data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}" data-start-date="2023-04-17T15:21:46.6573400+03:00" data-end-date="2023-04-17T15:21:46.6574650+03:00">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.StartDateTimeOffset" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.EndDateTimeOffset" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" data-val="true" data-val-required="The Start DateTime Offset - End DateTime Offset field is required." id="DynamicFormExample_StartDateTimeOffset" name="DynamicFormExample.StartDateTimeOffset" value="Mon Apr 17 2023 15:21:46 GMT+0300"><input data-end-date="true" type="hidden" data-val="true" data-val-required="The EndDateTimeOffset field is required." id="DynamicFormExample_EndDateTimeOffset" name="DynamicFormExample.EndDateTimeOffset" value="Mon Apr 17 2023 15:21:46 GMT+0300">
|
||||
</abp-date-range-picker>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DynamicFormExample_NullableStartDateTimeOffset">Nullable Start DateTime Offset - Nullable End DateTime Offset</label>
|
||||
<abp-date-range-picker id="MyPicker4" data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableStartDateTimeOffset" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableEndDateTimeOffset" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="DynamicFormExample_NullableStartDateTimeOffset" name="DynamicFormExample.NullableStartDateTimeOffset" value=""><input data-end-date="true" type="hidden" id="DynamicFormExample_NullableEndDateTimeOffset" name="DynamicFormExample.NullableEndDateTimeOffset" value="">
|
||||
</abp-date-range-picker>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DynamicFormExample_StringStartDate">String Start Date - String End Date</label>
|
||||
<abp-date-range-picker id="MyPicker5" data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.StringStartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.StringEndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="DynamicFormExample_StringStartDate" name="DynamicFormExample.StringStartDate" value=""><input data-end-date="true" type="hidden" id="DynamicFormExample_StringEndDate" name="DynamicFormExample.StringEndDate" value="">
|
||||
</abp-date-range-picker>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DynamicFormExample_DateTime">DateTime</label>
|
||||
<abp-date-picker data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}" data-date="2023-04-17T15:21:46.6572040+03:00">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.DateTime" data-valmsg-replace="true"></span><input data-date="true" type="hidden" data-val="true" data-val-required="The DateTime field is required." id="DynamicFormExample_DateTime" name="DynamicFormExample.DateTime" value="Mon Apr 17 2023 15:21:46 GMT+0300">
|
||||
</abp-date-picker>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DynamicFormExample_NullableDateTime">Nullable DateTime</label>
|
||||
<abp-date-picker data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableDateTime" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="DynamicFormExample_NullableDateTime" name="DynamicFormExample.NullableDateTime" value="">
|
||||
</abp-date-picker>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DynamicFormExample_DateTimeDateTimeOffset">DateTime DateTime Offset</label>
|
||||
<abp-date-picker data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}" data-date="2023-04-17T15:21:46.6575990+03:00">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.DateTimeDateTimeOffset" data-valmsg-replace="true"></span><input data-date="true" type="hidden" data-val="true" data-val-required="The DateTime DateTime Offset field is required." id="DynamicFormExample_DateTimeDateTimeOffset" name="DynamicFormExample.DateTimeDateTimeOffset" value="Mon Apr 17 2023 15:21:46 GMT+0300">
|
||||
</abp-date-picker>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DynamicFormExample_NullableDateTimeDateTimeOffset">Nullable DateTime DateTime Offset</label>
|
||||
<abp-date-picker data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableDateTimeDateTimeOffset" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="DynamicFormExample_NullableDateTimeDateTimeOffset" name="DynamicFormExample.NullableDateTimeDateTimeOffset" value="">
|
||||
</abp-date-picker>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="DynamicFormExample_StringDate">String Date</label>
|
||||
<abp-date-picker data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
|
||||
<div class="input-group">
|
||||
<input type="text" autocomplete="off" class="form-control">
|
||||
<button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.StringDate" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="DynamicFormExample_StringDate" name="DynamicFormExample.StringDate" value="">
|
||||
</abp-date-picker>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</code></pre>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker;
|
||||
|
||||
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components;
|
||||
|
||||
public class DatePickerModel : PageModel
|
||||
{
|
||||
|
||||
[BindProperty]
|
||||
[DisplayName("Start Date - End Date")]
|
||||
public DateTime StartDate { get; set; }
|
||||
[BindProperty]
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTime DateTime { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DisplayName("Nullable Start Date - Nullable End Date")]
|
||||
public DateTime? NullableStartDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTime? NullableEndDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DisplayName("Nullable DateTime")]
|
||||
public DateTime? NullableDateTime { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DisplayName("Start DateTime Offset - End DateTime Offset")]
|
||||
public DateTimeOffset StartDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTimeOffset EndDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DisplayName("DateTime DateTime Offset")]
|
||||
public DateTimeOffset DateTimeDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DisplayName("Nullable Start DateTime Offset - Nullable End DateTime Offset")]
|
||||
public DateTimeOffset? NullableStartDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTimeOffset? NullableEndDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DisplayName("Nullable DateTime DateTime Offset")]
|
||||
public DateTimeOffset? NullableDateTimeDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DisplayName("String Start Date - String End Date")]
|
||||
public string StringStartDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string StringEndDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DisplayName("String Date")]
|
||||
public string StringDate { get; set; }
|
||||
|
||||
public class DynamicForm
|
||||
{
|
||||
[BindProperty]
|
||||
[DateRangePicker("MyPicker",true)]
|
||||
[DisplayName("Start Date - End Date")]
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DateRangePicker("MyPicker",false)]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
public DateTime DateTime { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker2",true)]
|
||||
[DisplayName("Nullable Start Date - Nullable End Date")]
|
||||
public DateTime? NullableStartDate { get; set; }
|
||||
[BindProperty]
|
||||
[DateRangePicker("MyPicker2")]
|
||||
public DateTime? NullableEndDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DisplayName("Nullable DateTime")]
|
||||
public DateTime? NullableDateTime { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker3",true)]
|
||||
[DisplayName("Start DateTime Offset - End DateTime Offset")]
|
||||
public DateTimeOffset StartDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker3")]
|
||||
public DateTimeOffset EndDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DisplayName("DateTime DateTime Offset")]
|
||||
public DateTimeOffset DateTimeDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker4",true)]
|
||||
[DisplayName("Nullable Start DateTime Offset - Nullable End DateTime Offset")]
|
||||
public DateTimeOffset? NullableStartDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker4")]
|
||||
public DateTimeOffset? NullableEndDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DisplayName("Nullable DateTime DateTime Offset")]
|
||||
public DateTimeOffset? NullableDateTimeDateTimeOffset { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker5",true)]
|
||||
[DisplayName("String Start Date - String End Date")]
|
||||
public string StringStartDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DateRangePicker("MyPicker5")]
|
||||
public string StringEndDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[DatePickerOptions(nameof(DatePickerOptions))]
|
||||
[DatePicker]
|
||||
[DisplayName("String Date")]
|
||||
public string StringDate { get; set; }
|
||||
}
|
||||
|
||||
public AbpDatePickerOptions DatePickerOptions { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DynamicForm DynamicFormExample { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
StartDate = StartDate == default ? DateTime.Now : StartDate;
|
||||
EndDate = EndDate == default ? DateTime.Now : EndDate;
|
||||
DateTime = DateTime == default ? DateTime.Now : DateTime;
|
||||
|
||||
StartDateTimeOffset = StartDateTimeOffset == default ? DateTimeOffset.Now : StartDateTimeOffset;
|
||||
EndDateTimeOffset = EndDateTimeOffset == default ? DateTimeOffset.Now : EndDateTimeOffset;
|
||||
DateTimeDateTimeOffset = DateTimeDateTimeOffset == default ? DateTimeOffset.Now : DateTimeDateTimeOffset;
|
||||
|
||||
|
||||
DynamicFormExample ??= new DynamicForm {
|
||||
StartDate = DateTime.Now,
|
||||
EndDate = DateTime.Now,
|
||||
DateTime = DateTime.Now,
|
||||
StartDateTimeOffset = DateTimeOffset.Now,
|
||||
EndDateTimeOffset = DateTimeOffset.Now,
|
||||
DateTimeDateTimeOffset = DateTimeOffset.Now,
|
||||
};
|
||||
|
||||
|
||||
DatePickerOptions = new AbpDatePickerOptions();
|
||||
DatePickerOptions.LinkedCalendars = false;
|
||||
DatePickerOptions.Ranges = new List<AbpDatePickerRange>();
|
||||
DatePickerOptions.Ranges.Add(new AbpDatePickerRange("Today", DateTime.Now, DateTime.Now));
|
||||
}
|
||||
|
||||
public void OnPost()
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
@ -1,34 +1,221 @@
|
||||
@page
|
||||
@model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.IndexModel
|
||||
@{
|
||||
ViewData["Title"] = "Index";
|
||||
ViewData["Title"] = "Bootstrap Tag Helpers";
|
||||
}
|
||||
|
||||
<h2>Components</h2>
|
||||
|
||||
<ul>
|
||||
<li><a asp-page="Components/alerts">Alerts</a></li>
|
||||
<li><a asp-page="Components/badges">Badges</a></li>
|
||||
@*<li><a asp-page="Components/blockquotes"> > Blockquotes</a></li>*@
|
||||
<li><a asp-page="Components/Borders">Borders</a></li>
|
||||
<li><a asp-page="Components/breadcrumbs">Breadcrumbs</a></li>
|
||||
<li><a asp-page="Components/Buttons">Buttons</a></li>
|
||||
<li><a asp-page="Components/ButtonGroups">Button Groups</a></li>
|
||||
<li><a asp-page="Components/Cards">Cards</a></li>
|
||||
<li><a asp-page="Components/Carousel">Carousel</a></li>
|
||||
<li><a asp-page="Components/collapse">Collapse</a></li>
|
||||
<li><a asp-page="Components/Dropdowns">Dropdowns</a></li>
|
||||
<li><a asp-page="Components/DynamicForms">Dynamic Forms</a></li>
|
||||
<li><a asp-page="Components/FormElements">Form Elements</a></li>
|
||||
<li><a asp-page="Components/Grids">Grids</a></li>
|
||||
<li><a asp-page="Components/ListGroup">List Groups</a></li>
|
||||
<li><a asp-page="Components/Modals">Modals</a></li>
|
||||
<li><a asp-page="Components/Navs">Navs</a></li>
|
||||
<li><a asp-page="Components/Paginator">Paginator</a></li>
|
||||
<li><a asp-page="Components/Popovers">Popovers</a></li>
|
||||
<li><a asp-page="Components/ProgressBars">Progress Bars</a></li>
|
||||
<li><a asp-page="Components/Tables">Tables</a></li>
|
||||
<li><a asp-page="Components/Tabs">Tabs</a></li>
|
||||
<li><a asp-page="Components/tooltips">Tooltips</a></li>
|
||||
</ul>
|
||||
@section styles {
|
||||
<abp-style src="/Pages/Index.css"/>
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
<div class="row p-3">
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Alerts">Alerts</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Badges">Badges</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Borders">Borders</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Breadcrumbs">Breadcrumbs</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Buttons">Buttons</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/ButtonGroups">Button Groups</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Cards">Cards</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Carousel">Carousel</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Collapse">Collapse</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-3" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/DatePicker">Date Picker & Date Range Picker</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Dropdowns">Dropdowns</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/DynamicForms">Dynamic Forms</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/FormElements">Form Elements</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Grids">Grids</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/ListGroup">List Groups</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Modals">Modals</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Navs">Navs</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Paginator">Paginator</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Popovers">Popovers</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/ProgressBars">Progress Bars</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Tables">Tables</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Tabs">Tabs</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<abp-card class="text-center p-4" style="width: 15rem; height: 7rem;">
|
||||
<abp-card-body>
|
||||
<abp-card-title>
|
||||
<a abp-card-link asp-page="Components/Tooltips">Tooltips</a>
|
||||
</abp-card-title>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,4 @@
|
||||
a{
|
||||
color:black;
|
||||
text-decoration: none;
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
trigger:
|
||||
tags:
|
||||
include:
|
||||
- "*.*.*"
|
||||
|
||||
resources:
|
||||
repositories:
|
||||
- repository: devops
|
||||
type: github
|
||||
endpoint: github.com_skoc10
|
||||
name: volosoft/devops
|
||||
ref: master
|
||||
|
||||
variables:
|
||||
# Container registry service connection established during pipeline creation
|
||||
dockerRegistryServiceConnection: 'volosoft-reg'
|
||||
workDir: '$(Build.SourcesDirectory)'
|
||||
bootstrapTaghelpersDir: '$(workDir)/abp/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo'
|
||||
# tag: $[replace(variables['Build.SourceBranch'], 'refs/tags/', '')]
|
||||
tag: $(Build.BuildNumber)
|
||||
DOCKER_BUILDKIT: 1
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
|
||||
stages:
|
||||
- stage: Package
|
||||
displayName: Package
|
||||
jobs:
|
||||
- job: Build
|
||||
displayName: Package Helm Charts and Values
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- checkout: self
|
||||
- checkout: devops
|
||||
|
||||
- script: |
|
||||
cd $(bootstrapTaghelpersDir) && dotnet publish -c Release -o bin/Release/publish
|
||||
|
||||
- task: Docker@2
|
||||
displayName: Build Image
|
||||
inputs:
|
||||
command: build
|
||||
repository: demo/bootstrap-taghelpers
|
||||
dockerfile: $(bootstrapTaghelpersDir)/Dockerfile
|
||||
buildContext: $(bootstrapTaghelpersDir)
|
||||
containerRegistry: $(dockerRegistryServiceConnection)
|
||||
tags: |
|
||||
$(tag)
|
||||
|
||||
- task: Docker@2
|
||||
displayName: Push Image
|
||||
inputs:
|
||||
command: push
|
||||
repository: demo/bootstrap-taghelpers
|
||||
containerRegistry: $(dockerRegistryServiceConnection)
|
||||
tags: |
|
||||
$(tag)
|
||||
|
||||
- bash: |
|
||||
mkdir -p $(Build.SourcesDirectory)/devops/aks/versions
|
||||
|
||||
|
||||
cat <<EOF > $(Build.SourcesDirectory)/devops/aks/versions/bootstrap-taghelpers-version.yaml
|
||||
image:
|
||||
repository: volosoft.azurecr.io/demo/bootstrap-taghelpers
|
||||
tag: "$(tag)"
|
||||
EOF
|
||||
|
||||
cat $(Build.SourcesDirectory)/devops/aks/versions/bootstrap-taghelpers-version.yaml >> $(Build.SourcesDirectory)/devops/aks/helm/values/app/demo/bootstrap-taghelpers.abp.io.yaml
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Artifact: bootstrap-taghelpers'
|
||||
inputs:
|
||||
PathtoPublish: '$(Build.SourcesDirectory)/devops/aks/helm'
|
||||
ArtifactName: 'bootstrap-taghelpers'
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI
|
||||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
|
||||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
|
||||
@addTagHelper *, Volo.Blogging.Web
|
@ -0,0 +1,10 @@
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Volo.Blogging.Posts;
|
||||
|
||||
namespace Volo.Blogging.Members;
|
||||
|
||||
public interface IMemberAppService : IApplicationService
|
||||
{
|
||||
Task<BlogUserDto> FindAsync(string username);
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
using Volo.Blogging.Posts;
|
||||
using Volo.Blogging.Users;
|
||||
|
||||
namespace Volo.Blogging.Members;
|
||||
|
||||
public class MemberAppService : BloggingAppServiceBase, IMemberAppService
|
||||
{
|
||||
private readonly IRepository<BlogUser, Guid> _userRepository;
|
||||
|
||||
public MemberAppService(IRepository<BlogUser, Guid> userRepository)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
}
|
||||
|
||||
public async Task<BlogUserDto> FindAsync(string username)
|
||||
{
|
||||
var user = await _userRepository.FindAsync(x => x.UserName == username);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ObjectMapper.Map<BlogUser, BlogUserDto>(user);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Http.Client;
|
||||
using Volo.Abp.Http.Modeling;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Http.Client.ClientProxying;
|
||||
using Volo.Blogging.Blogs;
|
||||
using Volo.Blogging.Blogs.Dtos;
|
||||
using Volo.Blogging.Members;
|
||||
using Volo.Blogging.Posts;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Volo.Blogging.ClientProxies;
|
||||
|
||||
[Dependency(ReplaceServices = true)]
|
||||
[ExposeServices(typeof(IMemberAppService), typeof(MembersClientProxy))]
|
||||
public partial class MembersClientProxy : ClientProxyBase<IMemberAppService>, IMemberAppService
|
||||
{
|
||||
public Task<BlogUserDto> FindAsync(string username)
|
||||
{
|
||||
return RequestAsync<BlogUserDto>(nameof(FindAsync), new ClientProxyRequestTypeValue
|
||||
{
|
||||
{ typeof(string), username }
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
// This file is part of MembersClientProxy, you can customize it here
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Volo.Blogging.ClientProxies;
|
||||
|
||||
public partial class MembersClientProxy
|
||||
{
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
@page
|
||||
@using Microsoft.Extensions.Localization
|
||||
@using Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
|
||||
@using Volo.Abp.Users
|
||||
@using Volo.Blogging.Localization
|
||||
@model Volo.Blogging.Pages.Members.IndexModel
|
||||
@inject IStringLocalizer<BloggingResource> L
|
||||
@inject ICurrentUser CurrentUser
|
||||
@{
|
||||
ViewBag.Title = @Model.User.UserName.ToUpper() + " - " + L["Blogs"].Value;
|
||||
}
|
||||
|
||||
@section styles {
|
||||
<abp-style src="/Pages/Members/Index.css"/>
|
||||
}
|
||||
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="row gx-lg-5">
|
||||
<div class="col-md-4 mb-5 mb-md-0">
|
||||
<div class="card h-auto member-profile-info">
|
||||
<div class="card-body">
|
||||
<div class="d-inline-block position-relative">
|
||||
<img gravatar-email="@Model.User.Email" default-image="Identicon" class="post-member-img rounded-circle d-block"/>
|
||||
</div>
|
||||
@if (Model.User.UserName != null)
|
||||
{
|
||||
<h2 class="m-0">@Model.User.UserName</h2>
|
||||
}
|
||||
<small class="d-block mt-4">@L["UserName"].Value.ToUpper()</small>
|
||||
<h5>@Model.User.UserName</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (Model.Posts is not null && Model.Posts.Any())
|
||||
{
|
||||
<div class="col-md-8">
|
||||
<abp-tabs>
|
||||
<abp-tab name="all-posts" title="All Blog Posts">
|
||||
<div class="mt-4 pt-3">
|
||||
@foreach (var post in Model.Posts)
|
||||
{
|
||||
<div class="post-item">
|
||||
<div class="post-type-cont">
|
||||
|
||||
<a href="@Model.GetMemberProfileUrl(Model.User)" class="text-decoration-none">
|
||||
<img gravatar-email="@Model.User.Email" default-image="Identicon" class="post-member-img rounded-circle d-block"/>
|
||||
</a>
|
||||
<span class="post-type">
|
||||
<i class="fas fa-pen-nib"></i>
|
||||
@L["Blog"].Value.ToUpper()
|
||||
</span>
|
||||
</div>
|
||||
<div class="post-detail-cont">
|
||||
<div class="post-info fs-12 mb-2">
|
||||
<a href="@Model.GetMemberProfileUrl(Model.User)" class="text-decoration-none">
|
||||
<span class="text-dark dot">@Model.User.UserName</span>
|
||||
</a>
|
||||
<span class="text-dark-200 dot">@post.CreationTime.ToString("MMMM yyyy")</span>
|
||||
<span class="text-dark-200">@post.ReadCount.ToString() @L["Views"]</span>
|
||||
</div>
|
||||
<h3 class="post-title mb-3">
|
||||
<a href="@Model.GetBlogPostUrl(post)">
|
||||
@post.Title
|
||||
</a>
|
||||
</h3>
|
||||
<p class="post-desc">
|
||||
<a href="@Model.GetBlogPostUrl(post)">
|
||||
@post.Description.TruncateWithPostfix(150)
|
||||
</a>
|
||||
<a href="@Model.GetBlogPostUrl(post)" class="readMore">@L["ReadMore"]</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="post-img-cont">
|
||||
<div class="post-list-span text-center post">
|
||||
<img src="@post.CoverImage" class="box-articles">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</abp-tab>
|
||||
</abp-tabs>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="col-md-8">
|
||||
<div class="mt-5 pt-6">
|
||||
<p>@L["MemberNotPublishedPostYet"]</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
|
||||
using Volo.Blogging.Blogs;
|
||||
using Volo.Blogging.Members;
|
||||
using Volo.Blogging.Posts;
|
||||
|
||||
namespace Volo.Blogging.Pages.Members;
|
||||
|
||||
public class IndexModel : AbpPageModel
|
||||
{
|
||||
private readonly IPostAppService _postAppService;
|
||||
|
||||
private readonly IMemberAppService _memberAppService;
|
||||
|
||||
private readonly IBlogAppService _blogAppService;
|
||||
|
||||
public BlogUserDto User { get; set; }
|
||||
public List<PostWithDetailsDto> Posts { get; set; }
|
||||
|
||||
public Dictionary<Guid, string> BlogShortNameMap { get; set; }
|
||||
|
||||
public IndexModel(IPostAppService postAppService, IMemberAppService memberAppService, IBlogAppService blogAppService)
|
||||
{
|
||||
_postAppService = postAppService;
|
||||
_memberAppService = memberAppService;
|
||||
_blogAppService = blogAppService;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnGetAsync(string userName)
|
||||
{
|
||||
User = await _memberAppService.FindAsync(userName);
|
||||
|
||||
if (User is null)
|
||||
{
|
||||
return Redirect("/");
|
||||
}
|
||||
|
||||
Posts = await _postAppService.GetListByUserIdAsync(User.Id);
|
||||
|
||||
var blogIds = Posts.Select(x => x.BlogId).Distinct();
|
||||
BlogShortNameMap = new Dictionary<Guid, string>();
|
||||
|
||||
foreach (var blogId in blogIds)
|
||||
{
|
||||
BlogShortNameMap[blogId] = (await _blogAppService.GetAsync(blogId)).ShortName;
|
||||
}
|
||||
|
||||
return Page();
|
||||
}
|
||||
public string GetBlogPostUrl(PostWithDetailsDto post)
|
||||
{
|
||||
var blogShortName = BlogShortNameMap[post.BlogId];
|
||||
|
||||
return "/" + blogShortName + "/" + post.Url;
|
||||
}
|
||||
|
||||
public string GetMemberProfileUrl(BlogUserDto user)
|
||||
{
|
||||
return "/members/" + user.UserName;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
.post-desc {
|
||||
overflow-wrap: break-word;
|
||||
}
|