From 2cb93fbd977fbc8e8a62c28abf4481850b954e55 Mon Sep 17 00:00:00 2001 From: sumeyye Date: Wed, 17 Jun 2026 08:37:26 +0300 Subject: [PATCH] update: some upgrade enhancements for the cms-kit --- .../blog-post-form.component.html | 15 ++-- .../blog-post-form.component.ts | 63 ++++++++------ .../blog-post-list.component.html | 8 +- .../blog-post-list.component.ts | 55 ++++++------ .../blog-features-modal.component.html | 10 +-- .../blog-features-modal.component.ts | 55 ++++++------ .../blogs/blog-list/blog-list.component.html | 12 +-- .../blogs/blog-list/blog-list.component.ts | 79 ++++++++--------- .../blog-modal/blog-modal.component.html | 2 +- .../blogs/blog-modal/blog-modal.component.ts | 22 +++-- .../cms-settings/cms-settings.component.html | 2 +- .../cms-settings/cms-settings.component.ts | 10 +-- .../comment-details.component.html | 6 +- .../comment-details.component.ts | 46 +++++----- .../comment-list/comment-list.component.html | 2 +- .../comment-list/comment-list.component.ts | 34 ++++---- .../global-resources.component.html | 2 +- .../global-resources.component.ts | 14 ++- .../menu-item-list.component.html | 18 ++-- .../menu-item-list.component.ts | 69 +++++++-------- .../menu-item-modal.component.html | 20 ++--- .../menu-item-modal.component.ts | 85 ++++++++++--------- .../pages/page-form/page-form.component.html | 4 +- .../pages/page-form/page-form.component.ts | 41 +++++---- .../pages/page-list/page-list.component.html | 8 +- .../pages/page-list/page-list.component.ts | 51 +++++------ .../tags/tag-list/tag-list.component.html | 8 +- .../tags/tag-list/tag-list.component.ts | 77 +++++++---------- .../tags/tag-modal/tag-modal.component.ts | 11 ++- .../code-mirror-editor.component.ts | 10 ++- .../toast-ui/toastui-editor.component.ts | 8 +- 31 files changed, 444 insertions(+), 403 deletions(-) diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-form/blog-post-form.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-form/blog-post-form.component.html index 8d2138f906..fc8048fd41 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-form/blog-post-form.component.html +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-form/blog-post-form.component.html @@ -1,13 +1,13 @@
- @if (form && (!isEditMode || blogPost)) { + @if (form && (!isEditMode() || blogPost())) {
- @if (coverImagePreview) { + @if (coverImagePreview()) {
- Cover Image + Cover Image
- +
@@ -38,14 +38,15 @@ - @if (isTagsEnabled) { + @if (isTagsEnabled()) {
@@ -63,7 +64,7 @@ - @if (isEditMode) { + @if (isEditMode()) { {{ 'CmsKit::Publish' | abpLocalization }} diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-form/blog-post-form.component.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-form/blog-post-form.component.ts index 36a7cc2629..14b996a507 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-form/blog-post-form.component.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-form/blog-post-form.component.ts @@ -1,6 +1,14 @@ import { CommonModule } from '@angular/common'; import { ActivatedRoute } from '@angular/router'; -import { Component, OnInit, inject, Injector, DestroyRef } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + DestroyRef, + inject, + Injector, + OnInit, + signal, +} from '@angular/core'; import { ReactiveFormsModule, FormsModule, FormGroup, FormControl } from '@angular/forms'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { NgxValidateCoreModule } from '@ngx-validate/core'; @@ -29,6 +37,7 @@ import { eCmsKitAdminComponents } from '../../../enums'; import { BlogPostFormService } from '../../../services'; @Component({ + changeDetection: ChangeDetectionStrategy.OnPush, selector: 'abp-blog-post-form', templateUrl: './blog-post-form.component.html', providers: [ @@ -60,33 +69,33 @@ export class BlogPostFormComponent implements OnInit { private destroyRef = inject(DestroyRef); form: FormGroup; - blogPost: BlogPostDto | null = null; + readonly blogPost = signal(null); blogPostId: string | null = null; - isEditMode = false; + readonly isEditMode = signal(false); coverImageFile: File | null = null; - coverImagePreview: string | null = null; - tags: string = ''; - isTagsEnabled = true; + readonly coverImagePreview = signal(null); + readonly tags = signal(''); + readonly isTagsEnabled = signal(true); readonly BLOG_POST_ENTITY_TYPE = 'BlogPost'; ngOnInit() { const id = this.route.snapshot.params['id']; if (id) { - this.isEditMode = true; + this.isEditMode.set(true); this.blogPostId = id; this.loadBlogPost(id); } else { - this.isEditMode = false; + this.isEditMode.set(false); this.buildForm(); } } private loadBlogPost(id: string) { this.blogPostService.get(id).subscribe(blogPost => { - this.blogPost = blogPost; + this.blogPost.set(blogPost); if (blogPost.coverImageMediaId) { - this.coverImagePreview = `/api/cms-kit/media/${blogPost.coverImageMediaId}`; + this.coverImagePreview.set(`/api/cms-kit/media/${blogPost.coverImageMediaId}`); } this.buildForm(); this.loadTags(id); @@ -94,7 +103,6 @@ export class BlogPostFormComponent implements OnInit { } private loadTags(blogPostId: string) { - // TODO: use the public service to load the tags this.restService .request({ method: 'GET', @@ -102,28 +110,27 @@ export class BlogPostFormComponent implements OnInit { }) .subscribe(tags => { if (tags && tags.length > 0) { - this.tags = tags.map(t => t.name || '').join(', '); + this.tags.set(tags.map(t => t.name || '').join(', ')); } }); } private buildForm() { - const data = new FormPropData(this.injector, this.blogPost || {}); + const currentBlogPost = this.blogPost(); + const data = new FormPropData(this.injector, currentBlogPost || {}); const baseForm = generateFormFromProps(data); this.form = new FormGroup({ ...baseForm.controls, - content: new FormControl(this.blogPost?.content || ''), - coverImageMediaId: new FormControl(this.blogPost?.coverImageMediaId || null), + content: new FormControl(currentBlogPost?.content || ''), + coverImageMediaId: new FormControl(currentBlogPost?.coverImageMediaId || null), }); prepareSlugFromControl(this.form, 'title', 'slug', this.destroyRef); - // Check if tags feature is enabled for the blog - const blogId = this.form.get('blogId')?.value || this.blogPost?.blogId; + const blogId = this.form.get('blogId')?.value || currentBlogPost?.blogId; if (blogId) { this.checkTagsFeature(blogId); } - // Listen for blog selection changes this.form .get('blogId') ?.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)) @@ -142,7 +149,7 @@ export class BlogPostFormComponent implements OnInit { }) .subscribe(feature => { const { isEnabled } = feature || {}; - this.isTagsEnabled = isEnabled; + this.isTagsEnabled.set(isEnabled); }); } @@ -152,7 +159,7 @@ export class BlogPostFormComponent implements OnInit { this.coverImageFile = input.files[0]; const reader = new FileReader(); reader.onload = (e: any) => { - this.coverImagePreview = e.target.result; + this.coverImagePreview.set(e.target.result); }; reader.readAsDataURL(this.coverImageFile); } @@ -160,7 +167,7 @@ export class BlogPostFormComponent implements OnInit { removeCoverImage() { this.coverImageFile = null; - this.coverImagePreview = null; + this.coverImagePreview.set(null); this.form.patchValue({ coverImageMediaId: null }); } @@ -183,11 +190,12 @@ export class BlogPostFormComponent implements OnInit { } private setTags(blogPostId: string) { - if (!this.tags || !this.tags.trim()) { + const tagsValue = this.tags(); + if (!tagsValue || !tagsValue.trim()) { return of(null); } - const tagArray = this.tags + const tagArray = tagsValue .split(',') .map(t => t.trim()) .filter(t => t.length > 0); @@ -204,7 +212,6 @@ export class BlogPostFormComponent implements OnInit { } private executeSaveOperation(operation: 'save' | 'draft' | 'publish' | 'sendToReview') { - // First upload cover image if selected this.uploadCoverImage() .pipe( tap(coverImageMediaId => { @@ -213,11 +220,12 @@ export class BlogPostFormComponent implements OnInit { } }), switchMap(() => { - if (this.isEditMode) { - if (!this.blogPost || !this.blogPostId) { + if (this.isEditMode()) { + const currentBlogPost = this.blogPost(); + if (!currentBlogPost || !this.blogPostId) { return of(null); } - return this.blogPostFormService.update(this.blogPostId, this.form, this.blogPost); + return this.blogPostFormService.update(this.blogPostId, this.form, currentBlogPost); } switch (operation) { @@ -236,7 +244,6 @@ export class BlogPostFormComponent implements OnInit { if (!result || !result.id) { return of(null); } - // Set tags after blog post is created/updated return forkJoin([of(result), this.setTags(result.id)]); }), ) diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-list/blog-post-list.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-list/blog-post-list.component.html index 9c8b768945..47f2632cf8 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-list/blog-post-list.component.html +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-list/blog-post-list.component.html @@ -1,4 +1,4 @@ - +
@@ -35,6 +35,10 @@
- +
diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-list/blog-post-list.component.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-list/blog-post-list.component.ts index 67f90689f4..f14960df35 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-list/blog-post-list.component.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/blog-posts/blog-post-list/blog-post-list.component.ts @@ -1,4 +1,5 @@ -import { Component, OnInit, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { ListService, PagedResultDto, LocalizationPipe } from '@abp/ng.core'; @@ -14,6 +15,7 @@ import { import { eCmsKitAdminComponents } from '../../../enums'; @Component({ + changeDetection: ChangeDetectionStrategy.OnPush, selector: 'abp-blog-post-list', templateUrl: './blog-post-list.component.html', providers: [ @@ -25,21 +27,35 @@ import { eCmsKitAdminComponents } from '../../../enums'; ], imports: [ExtensibleTableComponent, PageComponent, LocalizationPipe, FormsModule, CommonModule], }) -export class BlogPostListComponent implements OnInit { - data: PagedResultDto = { items: [], totalCount: 0 }; - +export class BlogPostListComponent { public readonly list = inject(ListService); private blogPostService = inject(BlogPostAdminService); private confirmationService = inject(ConfirmationService); + readonly data = toSignal( + this.list.hookToQuery(query => { + let filters: Partial = {}; + if (this.list.filter) { + filters.filter = this.list.filter; + } + if (this.statusFilter !== null) { + filters.status = this.statusFilter; + } + const input: BlogPostGetListInput = { + ...query, + ...filters, + }; + return this.blogPostService.getList(input); + }), + { + initialValue: { items: [], totalCount: 0 } as PagedResultDto, + }, + ); + filter = ''; statusFilter: BlogPostStatus | null = null; BlogPostStatus = BlogPostStatus; - ngOnInit() { - this.hookToQuery(); - } - onSearch() { this.list.filter = this.filter; this.list.get(); @@ -49,25 +65,6 @@ export class BlogPostListComponent implements OnInit { this.list.get(); } - private hookToQuery() { - this.list - .hookToQuery(query => { - let filters: Partial = {}; - if (this.list.filter) { - filters.filter = this.list.filter; - } - if (this.statusFilter !== null) { - filters.status = this.statusFilter; - } - const input: BlogPostGetListInput = { - ...query, - ...filters, - }; - return this.blogPostService.getList(input); - }) - .subscribe(res => (this.data = res)); - } - delete(id: string, title: string) { this.confirmationService .warn('CmsKit::BlogPostDeletionConfirmationMessage', 'AbpUi::AreYouSure', { @@ -77,9 +74,7 @@ export class BlogPostListComponent implements OnInit { }) .subscribe((status: Confirmation.Status) => { if (status === Confirmation.Status.confirm) { - this.blogPostService.delete(id).subscribe(() => { - this.list.get(); - }); + this.blogPostService.delete(id).subscribe(() => this.list.get()); } }); } diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-features-modal/blog-features-modal.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-features-modal/blog-features-modal.component.html index 77ccd60396..1f04f5073e 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-features-modal/blog-features-modal.component.html +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-features-modal/blog-features-modal.component.html @@ -4,8 +4,8 @@ - @if (form) { -
+ @if (form(); as currentForm) { +
@for (featureControl of featuresFormArray.controls; track $index; let i = $index) {
@@ -19,7 +19,7 @@ formControlName="isEnabled" />
} @else { @@ -36,7 +36,7 @@ [disabled]="true" />
@@ -58,7 +58,7 @@ - + {{ 'AbpUi::Save' | abpLocalization }} diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-features-modal/blog-features-modal.component.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-features-modal/blog-features-modal.component.ts index 4b4bd4f420..30785fbeb5 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-features-modal/blog-features-modal.component.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-features-modal/blog-features-modal.component.ts @@ -1,4 +1,12 @@ -import { Component, OnInit, inject, input, output } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + inject, + input, + OnInit, + output, + signal, +} from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReactiveFormsModule, FormArray, FormBuilder, FormGroup } from '@angular/forms'; import { NgxValidateCoreModule } from '@ngx-validate/core'; @@ -22,6 +30,7 @@ export interface BlogFeaturesModalVisibleChange { } @Component({ + changeDetection: ChangeDetectionStrategy.OnPush, selector: 'abp-blog-features-modal', templateUrl: './blog-features-modal.component.html', imports: [ @@ -42,8 +51,8 @@ export class BlogFeaturesModalComponent implements OnInit { blogId = input(); visibleChange = output(); - form: FormGroup; - features: BlogFeatureDto[] = []; + readonly form = signal(undefined); + readonly features = signal([]); private initialFeatureStates: Map = new Map(); ngOnInit() { @@ -54,19 +63,19 @@ export class BlogFeaturesModalComponent implements OnInit { private loadFeatures() { this.blogFeatureService.getList(this.blogId()!).subscribe(features => { - this.features = features.sort((a, b) => + const sorted = features.sort((a, b) => (a.featureName || '').localeCompare(b.featureName || ''), ); - // Store initial states + this.features.set(sorted); this.initialFeatureStates = new Map( - this.features.map(f => [f.featureName || '', f.isEnabled || false]), + sorted.map(f => [f.featureName || '', f.isEnabled || false]), ); - this.buildForm(); + this.buildForm(sorted); }); } - private buildForm() { - const featureControls = this.features.map(feature => + private buildForm(features: BlogFeatureDto[]) { + const featureControls = features.map(feature => this.fb.group({ featureName: [feature.featureName], isEnabled: [feature.isEnabled], @@ -74,13 +83,15 @@ export class BlogFeaturesModalComponent implements OnInit { }), ); - this.form = this.fb.group({ - features: this.fb.array(featureControls), - }); + this.form.set( + this.fb.group({ + features: this.fb.array(featureControls), + }), + ); } get featuresFormArray(): FormArray { - return this.form.get('features') as FormArray; + return this.form()!.get('features') as FormArray; } onVisibleChange(visible: boolean, refresh = false) { @@ -88,20 +99,19 @@ export class BlogFeaturesModalComponent implements OnInit { } save() { - if (!this.form.valid || !this.blogId()) { + const currentForm = this.form(); + if (!currentForm?.valid || !this.blogId()) { return; } - const featuresArray = this.form.get('features') as FormArray; + const featuresArray = currentForm.get('features') as FormArray; - // Only save features that have changed const changedFeatures: BlogFeatureInputDto[] = featuresArray.controls .map(control => { const featureName = control.get('featureName')?.value; const isEnabled = control.get('isEnabled')?.value; const initialIsEnabled = this.initialFeatureStates.get(featureName); - // Only include if the value has changed if (featureName && initialIsEnabled !== isEnabled) { return { featureName, @@ -112,23 +122,18 @@ export class BlogFeaturesModalComponent implements OnInit { }) .filter((input): input is BlogFeatureInputDto => input !== null); - // If no features changed, just close the modal if (changedFeatures.length === 0) { this.onVisibleChange(false, false); return; } - // Save only changed features const saveObservables = changedFeatures.map(input => this.blogFeatureService.set(this.blogId()!, input), ); - // Use forkJoin to save all changed features at once - forkJoin(saveObservables).subscribe({ - next: () => { - this.onVisibleChange(false, true); - this.toasterService.success('AbpUi::SavedSuccessfully'); - }, + forkJoin(saveObservables).subscribe(() => { + this.onVisibleChange(false, true); + this.toasterService.success('AbpUi::SavedSuccessfully'); }); } } diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-list/blog-list.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-list/blog-list.component.html index e9f224383f..93c0819475 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-list/blog-list.component.html +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-list/blog-list.component.html @@ -1,15 +1,15 @@ - +
- +
- @if (isModalVisible) { - + @if (isModalVisible()) { + } - @if (isFeaturesModalVisible) { + @if (isFeaturesModalVisible()) { } diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-list/blog-list.component.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-list/blog-list.component.ts index 4b5c84495a..0fc9fb129e 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-list/blog-list.component.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-list/blog-list.component.ts @@ -1,4 +1,5 @@ -import { Component, OnInit, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { ListService, PagedResultDto, LocalizationPipe } from '@abp/ng.core'; @@ -14,6 +15,7 @@ import { } from '../blog-features-modal/blog-features-modal.component'; @Component({ + changeDetection: ChangeDetectionStrategy.OnPush, selector: 'abp-blog-list', templateUrl: './blog-list.component.html', providers: [ @@ -33,22 +35,33 @@ import { BlogFeaturesModalComponent, ], }) -export class BlogListComponent implements OnInit { - data: PagedResultDto = { items: [], totalCount: 0 }; - +export class BlogListComponent { public readonly list = inject(ListService); private blogService = inject(BlogAdminService); private confirmationService = inject(ConfirmationService); - filter = ''; - isModalVisible = false; - selected?: BlogDto; - isFeaturesModalVisible = false; - selectedBlogId?: string; + readonly data = toSignal( + this.list.hookToQuery(query => { + let filters: Partial = {}; + if (this.list.filter) { + filters.filter = this.list.filter; + } + const input: BlogGetListInput = { + ...query, + ...filters, + }; + return this.blogService.getList(input); + }), + { + initialValue: { items: [], totalCount: 0 } as PagedResultDto, + }, + ); - ngOnInit() { - this.hookToQuery(); - } + filter = ''; + readonly isModalVisible = signal(false); + readonly selected = signal(undefined); + readonly isFeaturesModalVisible = signal(false); + readonly selectedBlogId = signal(undefined); onSearch() { this.list.filter = this.filter; @@ -56,14 +69,14 @@ export class BlogListComponent implements OnInit { } add() { - this.selected = {} as BlogDto; - this.isModalVisible = true; + this.selected.set({} as BlogDto); + this.isModalVisible.set(true); } edit(id: string) { this.blogService.get(id).subscribe(blog => { - this.selected = blog; - this.isModalVisible = true; + this.selected.set(blog); + this.isModalVisible.set(true); }); } @@ -74,34 +87,14 @@ export class BlogListComponent implements OnInit { }) .subscribe((status: Confirmation.Status) => { if (status === Confirmation.Status.confirm) { - this.blogService.delete(id).subscribe(() => { - this.list.get(); - }); + this.blogService.delete(id).subscribe(() => this.list.get()); } }); } openFeatures(id: string) { - this.selectedBlogId = id; - this.isFeaturesModalVisible = true; - } - - private hookToQuery() { - this.list - .hookToQuery(query => { - let filters: Partial = {}; - if (this.list.filter) { - filters.filter = this.list.filter; - } - const input: BlogGetListInput = { - ...query, - ...filters, - }; - return this.blogService.getList(input); - }) - .subscribe(res => { - this.data = res; - }); + this.selectedBlogId.set(id); + this.isFeaturesModalVisible.set(true); } onVisibleModalChange(visibilityChange: BlogModalVisibleChange) { @@ -111,8 +104,8 @@ export class BlogListComponent implements OnInit { if (visibilityChange.refresh) { this.list.get(); } - this.selected = null; - this.isModalVisible = false; + this.selected.set(undefined); + this.isModalVisible.set(false); } onFeaturesModalChange(visibilityChange: BlogFeaturesModalVisibleChange) { @@ -122,7 +115,7 @@ export class BlogListComponent implements OnInit { if (visibilityChange.refresh) { this.list.get(); } - this.selectedBlogId = null; - this.isFeaturesModalVisible = false; + this.selectedBlogId.set(undefined); + this.isFeaturesModalVisible.set(false); } } diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-modal/blog-modal.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-modal/blog-modal.component.html index b6a7fe9412..f5d5ff7523 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-modal/blog-modal.component.html +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-modal/blog-modal.component.html @@ -1,4 +1,4 @@ - +

{{ (selected()?.id ? 'AbpUi::Edit' : 'AbpUi::New') | abpLocalization }} diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-modal/blog-modal.component.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-modal/blog-modal.component.ts index d9a4d07441..c87109f6ce 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-modal/blog-modal.component.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/blogs/blog-modal/blog-modal.component.ts @@ -1,4 +1,14 @@ -import { Component, OnInit, inject, Injector, input, output, DestroyRef } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + DestroyRef, + inject, + Injector, + input, + OnInit, + output, + signal, +} from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReactiveFormsModule, FormGroup } from '@angular/forms'; import { NgxValidateCoreModule } from '@ngx-validate/core'; @@ -24,6 +34,7 @@ export interface BlogModalVisibleChange { } @Component({ + changeDetection: ChangeDetectionStrategy.OnPush, selector: 'abp-blog-modal', templateUrl: './blog-modal.component.html', imports: [ @@ -46,7 +57,7 @@ export class BlogModalComponent implements OnInit { selected = input(); visibleChange = output(); - modalBusy = false; + readonly modalBusy = signal(false); form: FormGroup; @@ -65,12 +76,13 @@ export class BlogModalComponent implements OnInit { } save() { - if (this.modalBusy) { + if (this.modalBusy()) { return; } - this.modalBusy = true; + this.modalBusy.set(true); if (!this.form.valid) { + this.modalBusy.set(false); return; } @@ -86,7 +98,7 @@ export class BlogModalComponent implements OnInit { } as UpdateBlogDto); } - observable$.pipe(finalize(() => (this.modalBusy = false))).subscribe(() => { + observable$.pipe(finalize(() => this.modalBusy.set(false))).subscribe(() => { this.onVisibleChange(false, true); this.toasterService.success('AbpUi::SavedSuccessfully'); }); diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/cms-settings/cms-settings.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/cms-settings/cms-settings.component.html index 0f4cf1fd1d..6f54edd503 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/cms-settings/cms-settings.component.html +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/cms-settings/cms-settings.component.html @@ -28,7 +28,7 @@


- + {{ 'AbpAccount::Save' | abpLocalization }}
diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/cms-settings/cms-settings.component.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/cms-settings/cms-settings.component.ts index 0e12a005d0..38ccdd5ff5 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/cms-settings/cms-settings.component.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/cms-settings/cms-settings.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { NgbNav, @@ -33,12 +33,12 @@ import { CMS_KIT_COMMENTS_REQUIRE_APPROVEMENT } from '../comments'; ReactiveFormsModule, ], }) -export class CmsSettingsComponent { +export class CmsSettingsComponent implements OnInit { readonly commentAdminService = inject(CommentAdminService); readonly configState = inject(ConfigStateService); readonly toaster = inject(ToasterService); - loading = false; + readonly loading = signal(false); commentApprovalControl = new FormControl(false); @@ -49,12 +49,12 @@ export class CmsSettingsComponent { } submit() { - this.loading = true; + this.loading.set(true); this.commentAdminService .updateSettings({ commentRequireApprovement: this.commentApprovalControl.value }) .pipe( finalize(() => { - this.loading = false; + this.loading.set(false); this.configState.refreshAppState().subscribe(); }), ) diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.html index 7b4c18c4a3..708859176b 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.html +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.html @@ -1,5 +1,5 @@ - @if (comment) { + @if (comment(); as comment) {
@@ -59,7 +59,7 @@
- +
@@ -142,6 +142,6 @@

{{ 'CmsKit::RepliesToThisComment' | abpLocalization }}

- +
diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.ts index ffebe3ca2c..b9ff177e75 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.ts @@ -1,4 +1,5 @@ -import { Component, OnInit, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; import { CommonModule, DatePipe } from '@angular/common'; import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; @@ -18,6 +19,7 @@ import { eCmsKitAdminComponents } from '../../../enums'; import { CommentEntityService } from '../../../services'; @Component({ + changeDetection: ChangeDetectionStrategy.OnPush, selector: 'abp-comment-details', templateUrl: './comment-details.component.html', providers: [ @@ -46,8 +48,8 @@ import { CommentEntityService } from '../../../services'; ], }) export class CommentDetailsComponent implements OnInit { - comment: CommentWithAuthorDto | null = null; - data: PagedResultDto = { items: [], totalCount: 0 }; + readonly comment = signal(null); + readonly commentId = signal(null); readonly list = inject(ListService); readonly commentEntityService = inject(CommentEntityService); @@ -57,19 +59,33 @@ export class CommentDetailsComponent implements OnInit { private router = inject(Router); private fb = inject(FormBuilder); + readonly data = toSignal( + this.list.hookToQuery(query => { + const filters = (this.list.filter as Partial) || {}; + const input: CommentGetListInput = { + repliedCommentId: this.commentId() ?? undefined, + ...query, + ...filters, + }; + return this.commentService.getList(input); + }), + { + initialValue: { items: [], totalCount: 0 } as PagedResultDto, + }, + ); + filterForm!: FormGroup; commentApproveStateOptions = commentApproveStateOptions; - commentId!: string; requireApprovement: boolean; ngOnInit() { this.route.params.subscribe(params => { const id = params['id']; if (id) { - this.commentId = id; + this.commentId.set(id); this.loadComment(id); this.createFilterForm(); - this.hookToQuery(); + this.list.get(); } }); this.requireApprovement = this.commentEntityService.requireApprovement; @@ -86,7 +102,7 @@ export class CommentDetailsComponent implements OnInit { private loadComment(id: string) { this.commentService.get(id).subscribe(comment => { - this.comment = comment; + this.comment.set(comment); }); } @@ -95,7 +111,7 @@ export class CommentDetailsComponent implements OnInit { const filters: Partial = { author: formValue.author || undefined, commentApproveState: formValue.commentApproveState, - repliedCommentId: this.commentId, + repliedCommentId: this.commentId() ?? undefined, creationStartDate: formValue.creationStartDate || undefined, creationEndDate: formValue.creationEndDate || undefined, }; @@ -104,20 +120,6 @@ export class CommentDetailsComponent implements OnInit { this.list.get(); } - private hookToQuery() { - this.list - .hookToQuery(query => { - const filters = (this.list.filter as Partial) || {}; - const input: CommentGetListInput = { - repliedCommentId: this.commentId, - ...query, - ...filters, - }; - return this.commentService.getList(input); - }) - .subscribe(res => (this.data = res)); - } - navigateToReply(id: string) { this.router.navigate(['/cms/comments', id]); } diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.html index 5137014959..62d2eb5466 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.html +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.html @@ -87,6 +87,6 @@
- +
diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.ts index dc7da58d78..5ab7e299d5 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.ts @@ -1,4 +1,5 @@ -import { Component, OnInit, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; import { CommonModule } from '@angular/common'; import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms'; import { NgbDateAdapter, NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; @@ -17,6 +18,7 @@ import { eCmsKitAdminComponents } from '../../../enums'; import { CommentEntityService } from '../../../services'; @Component({ + changeDetection: ChangeDetectionStrategy.OnPush, selector: 'abp-comment-list', templateUrl: './comment-list.component.html', providers: [ @@ -44,21 +46,32 @@ import { CommentEntityService } from '../../../services'; ], }) export class CommentListComponent implements OnInit { - data: PagedResultDto = { items: [], totalCount: 0 }; - readonly list = inject(ListService); readonly commentEntityService = inject(CommentEntityService); private commentService = inject(CommentAdminService); private fb = inject(FormBuilder); + readonly data = toSignal( + this.list.hookToQuery(query => { + const filters = (this.list.filter as Partial) || {}; + const input: CommentGetListInput = { + ...query, + ...filters, + }; + return this.commentService.getList(input); + }), + { + initialValue: { items: [], totalCount: 0 } as PagedResultDto, + }, + ); + filterForm!: FormGroup; commentApproveStateOptions = commentApproveStateOptions; requireApprovement: boolean; ngOnInit() { this.createFilterForm(); - this.hookToQuery(); this.requireApprovement = this.commentEntityService.requireApprovement; } @@ -85,17 +98,4 @@ export class CommentListComponent implements OnInit { this.list.filter = filters as any; this.list.get(); } - - private hookToQuery() { - this.list - .hookToQuery(query => { - const filters = (this.list.filter as Partial) || {}; - const input: CommentGetListInput = { - ...query, - ...filters, - }; - return this.commentService.getList(input); - }) - .subscribe(res => (this.data = res)); - } } diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/global-resources/global-resources.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/global-resources/global-resources.component.html index 969bbbe6a8..5a132fea79 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/global-resources/global-resources.component.html +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/global-resources/global-resources.component.html @@ -6,7 +6,7 @@ ngbNav #nav="ngbNav" class="nav-tabs" - [(activeId)]="activeTab" + [activeId]="activeTab()" (activeIdChange)="onTabChange($event)" >
  • diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/global-resources/global-resources.component.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/global-resources/global-resources.component.ts index a620267220..93a8410e33 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/global-resources/global-resources.component.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/global-resources/global-resources.component.ts @@ -1,4 +1,11 @@ -import { Component, OnInit, inject, DestroyRef } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + DestroyRef, + inject, + OnInit, + signal, +} from '@angular/core'; import { ReactiveFormsModule, FormGroup, FormControl } from '@angular/forms'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { CommonModule } from '@angular/common'; @@ -15,6 +22,7 @@ import { } from '@abp/ng.cms-kit/proxy'; @Component({ + changeDetection: ChangeDetectionStrategy.OnPush, selector: 'abp-global-resources', imports: [ CommonModule, @@ -34,7 +42,7 @@ export class GlobalResourcesComponent implements OnInit { private destroyRef = inject(DestroyRef); form: FormGroup; - activeTab: string = 'script'; + readonly activeTab = signal('script'); ngOnInit() { this.buildForm(); @@ -66,7 +74,7 @@ export class GlobalResourcesComponent implements OnInit { } onTabChange(activeId: string) { - this.activeTab = activeId; + this.activeTab.set(activeId); } save() { diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-list/menu-item-list.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-list/menu-item-list.component.html index 11e2653aa6..d3a1ae9e4f 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-list/menu-item-list.component.html +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-list/menu-item-list.component.html @@ -1,12 +1,12 @@ - +
    - @if (nodes.length > 0) { + @if (nodes().length > 0) { -@if (isModalVisible) { +@if (isModalVisible()) { } diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-list/menu-item-list.component.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-list/menu-item-list.component.ts index 5f687113f5..d1ee31fc25 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-list/menu-item-list.component.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-list/menu-item-list.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core'; import { CommonModule } from '@angular/common'; import { of } from 'rxjs'; import { PageComponent } from '@abp/ng.components/page'; @@ -19,6 +19,7 @@ import { } from '../menu-item-modal/menu-item-modal.component'; @Component({ + changeDetection: ChangeDetectionStrategy.OnPush, selector: 'abp-menu-item-list', templateUrl: './menu-item-list.component.html', imports: [ @@ -41,13 +42,13 @@ export class MenuItemListComponent implements OnInit { private menuItemService = inject(MenuItemAdminService); private confirmationService = inject(ConfirmationService); - nodes: any[] = []; - selectedNode: MenuItemDto | null = null; - expandedKeys: string[] = []; - draggable = true; - isModalVisible = false; - selectedMenuItem: MenuItemDto | MenuItemWithDetailsDto | null = null; - parentId: string | null = null; + readonly nodes = signal([]); + readonly selectedNode = signal(null); + readonly expandedKeys = signal([]); + readonly draggable = signal(true); + readonly isModalVisible = signal(false); + readonly selectedMenuItem = signal(null); + readonly parentId = signal(null); ngOnInit() { this.loadMenuItems(); @@ -56,11 +57,12 @@ export class MenuItemListComponent implements OnInit { private loadMenuItems() { this.menuItemService.getList().subscribe(result => { if (result.items && result.items.length > 0) { - this.nodes = this.buildTreeNodes(result.items); - // Expand all nodes by default - this.expandedKeys = this.nodes.map(n => n.key); + const treeNodes = this.buildTreeNodes(result.items); + this.nodes.set(treeNodes); + this.expandedKeys.set(treeNodes.map(n => n.key)); } else { - this.nodes = []; + this.nodes.set([]); + this.expandedKeys.set([]); } }); } @@ -69,7 +71,6 @@ export class MenuItemListComponent implements OnInit { const nodeMap = new Map(); const rootNodes: any[] = []; - // First pass: create all nodes items.forEach(item => { const node: any = { key: item.id, @@ -81,7 +82,6 @@ export class MenuItemListComponent implements OnInit { nodeMap.set(item.id!, node); }); - // Second pass: build tree structure items.forEach(item => { const node = nodeMap.get(item.id!); if (item.parentId) { @@ -97,7 +97,6 @@ export class MenuItemListComponent implements OnInit { } }); - // Sort by order const sortByOrder = (nodes: any[]) => { nodes.sort((a, b) => (a.entity.order || 0) - (b.entity.order || 0)); nodes.forEach(node => { @@ -112,7 +111,7 @@ export class MenuItemListComponent implements OnInit { } onSelectedNodeChange(node: any) { - this.selectedNode = node?.entity || null; + this.selectedNode.set(node?.entity || null); } onDrop(event: any) { @@ -143,16 +142,10 @@ export class MenuItemListComponent implements OnInit { }; this.menuItemService.moveMenuItem(node.id!, input).subscribe({ - next: () => { - this.loadMenuItems(); - }, - error: () => { - // Reload to rollback - this.loadMenuItems(); - }, + next: () => this.loadMenuItems(), + error: () => this.loadMenuItems(), }); } else { - // Reload to rollback this.loadMenuItems(); } }); @@ -163,22 +156,22 @@ export class MenuItemListComponent implements OnInit { }; add() { - this.selectedMenuItem = null; - this.parentId = null; - this.isModalVisible = true; + this.selectedMenuItem.set(null); + this.parentId.set(null); + this.isModalVisible.set(true); } addSubMenuItem(parentId?: string) { - this.selectedMenuItem = null; - this.parentId = parentId || null; - this.isModalVisible = true; + this.selectedMenuItem.set(null); + this.parentId.set(parentId || null); + this.isModalVisible.set(true); } edit(id: string) { this.menuItemService.get(id).subscribe(menuItem => { - this.selectedMenuItem = menuItem; - this.parentId = null; - this.isModalVisible = true; + this.selectedMenuItem.set(menuItem); + this.parentId.set(null); + this.isModalVisible.set(true); }); } @@ -189,9 +182,9 @@ export class MenuItemListComponent implements OnInit { if (visibilityChange.refresh) { this.loadMenuItems(); } - this.selectedMenuItem = null; - this.parentId = null; - this.isModalVisible = false; + this.selectedMenuItem.set(null); + this.parentId.set(null); + this.isModalVisible.set(false); } delete(id: string, displayName?: string) { @@ -204,9 +197,7 @@ export class MenuItemListComponent implements OnInit { .subscribe((status: Confirmation.Status) => { if (status === Confirmation.Status.confirm) { this.menuItemService.delete(id).subscribe({ - next: () => { - this.loadMenuItems(); - }, + next: () => this.loadMenuItems(), }); } }); diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-modal/menu-item-modal.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-modal/menu-item-modal.component.html index ced5bf88fa..bd54ed05ab 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-modal/menu-item-modal.component.html +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/menus/menu-item-modal/menu-item-modal.component.html @@ -16,7 +16,7 @@ ngbNav #nav="ngbNav" class="nav-tabs" - [(activeId)]="activeTab" + [activeId]="activeTab()" (activeIdChange)="onTabChange($event)" >
  • @@ -51,9 +51,9 @@ type="button" id="pageSelectDropdown" ngbDropdownToggle - [class.text-muted]="!selectedPage" + [class.text-muted]="!selectedPage()" > - {{ selectedPage?.title || ('CmsKit::Page' | abpLocalization) }} + {{ selectedPage()?.title || ('CmsKit::Page' | abpLocalization) }} - @if (filteredPages.length > 0) { - @for (page of filteredPages; track page.id) { + @if (filteredPages().length > 0) { + @for (page of filteredPages(); track page.id) {