From 67ed01ee3f7a0f4d6a3d58f6952baaa4e7bf48d2 Mon Sep 17 00:00:00 2001 From: sumeyye Date: Mon, 17 Nov 2025 17:08:18 +0300 Subject: [PATCH] add: comments feature for the cms kit admin side --- .../admin/config/src/enums/route-names.ts | 2 +- .../cms-kit-admin-config.provider.ts | 2 +- .../config/src/providers/route.provider.ts | 16 +- .../cms-kit/admin/src/cms-kit-admin.routes.ts | 70 +++++++- .../comment-approve.component.html | 72 +++++++++ .../comment-approve.component.ts | 122 ++++++++++++++ .../comments/comment-approve/index.ts | 1 + .../comment-details.component.html | 147 +++++++++++++++++ .../comment-details.component.ts | 152 ++++++++++++++++++ .../comments/comment-details/index.ts | 1 + .../comment-list/comment-list.component.html | 91 +++++++++++ .../comment-list/comment-list.component.ts | 128 +++++++++++++++ .../components/comments/comment-list/index.ts | 1 + .../admin/src/components/comments/index.ts | 3 + .../cms-kit/admin/src/components/index.ts | 3 +- .../default-comment-entity-actions.ts | 62 +++++++ .../comments/default-comment-entity-props.ts | 78 +++++++++ .../admin/src/defaults/comments/index.ts | 2 + .../cms-kit/admin/src/defaults/index.ts | 1 + .../admin/src/models/config-options.ts | 28 +++- .../packages/cms-kit/admin/src/public-api.ts | 6 +- .../src/resolvers/extensions.resolver.ts | 53 +++++- .../admin/src/tokens/extensions.token.ts | 41 ++++- 23 files changed, 1051 insertions(+), 31 deletions(-) create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/comment-approve.component.html create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/comment-approve.component.ts create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/index.ts create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.html create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.ts create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/index.ts create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.html create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.ts create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/index.ts create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/components/comments/index.ts create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/default-comment-entity-actions.ts create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/default-comment-entity-props.ts create mode 100644 npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/index.ts diff --git a/npm/ng-packs/packages/cms-kit/admin/config/src/enums/route-names.ts b/npm/ng-packs/packages/cms-kit/admin/config/src/enums/route-names.ts index d5a502c2f5..446d79b557 100644 --- a/npm/ng-packs/packages/cms-kit/admin/config/src/enums/route-names.ts +++ b/npm/ng-packs/packages/cms-kit/admin/config/src/enums/route-names.ts @@ -1,5 +1,5 @@ export enum eCmsKitAdminRouteNames { - Comments = 'CmsKit::Menu:Comments', + Comments = 'CmsKit::CmsKit.Comments', Tags = 'CmsKit::Menu:Tags', Pages = 'CmsKit::Menu:Pages', Blogs = 'CmsKit::Menu:Blogs', diff --git a/npm/ng-packs/packages/cms-kit/admin/config/src/providers/cms-kit-admin-config.provider.ts b/npm/ng-packs/packages/cms-kit/admin/config/src/providers/cms-kit-admin-config.provider.ts index e8d6401535..119cca5a9a 100644 --- a/npm/ng-packs/packages/cms-kit/admin/config/src/providers/cms-kit-admin-config.provider.ts +++ b/npm/ng-packs/packages/cms-kit/admin/config/src/providers/cms-kit-admin-config.provider.ts @@ -1,4 +1,4 @@ -import { Provider, makeEnvironmentProviders } from '@angular/core'; +import { makeEnvironmentProviders } from '@angular/core'; import { CMS_KIT_ADMIN_ROUTE_PROVIDERS } from './route.provider'; export function provideCmsKitAdminConfig() { diff --git a/npm/ng-packs/packages/cms-kit/admin/config/src/providers/route.provider.ts b/npm/ng-packs/packages/cms-kit/admin/config/src/providers/route.provider.ts index 7fcb4acdd2..215e3534bd 100644 --- a/npm/ng-packs/packages/cms-kit/admin/config/src/providers/route.provider.ts +++ b/npm/ng-packs/packages/cms-kit/admin/config/src/providers/route.provider.ts @@ -14,16 +14,16 @@ export function configureRoutes() { const routesService = inject(RoutesService); routesService.add([ { - path: '/cms-kit/comments', + path: '/cms/comments', name: eCmsKitAdminRouteNames.Comments, - parentName: eThemeSharedRouteNames.Administration, + parentName: 'CmsKit::Menu:CMS', order: 100, layout: eLayoutType.application, iconClass: 'fa fa-comments', requiredPolicy: eCmsKitAdminPolicyNames.Comments, }, { - path: '/cms-kit/tags', + path: '/cms/tags', name: eCmsKitAdminRouteNames.Tags, parentName: eThemeSharedRouteNames.Administration, order: 101, @@ -32,7 +32,7 @@ export function configureRoutes() { requiredPolicy: eCmsKitAdminPolicyNames.Tags, }, { - path: '/cms-kit/pages', + path: '/cms/pages', name: eCmsKitAdminRouteNames.Pages, parentName: eThemeSharedRouteNames.Administration, order: 102, @@ -41,7 +41,7 @@ export function configureRoutes() { requiredPolicy: eCmsKitAdminPolicyNames.Pages, }, { - path: '/cms-kit/blogs', + path: '/cms/blogs', name: eCmsKitAdminRouteNames.Blogs, parentName: eThemeSharedRouteNames.Administration, order: 103, @@ -50,7 +50,7 @@ export function configureRoutes() { requiredPolicy: eCmsKitAdminPolicyNames.Blogs, }, { - path: '/cms-kit/blog-posts', + path: '/cms/blog-posts', name: eCmsKitAdminRouteNames.BlogPosts, parentName: eThemeSharedRouteNames.Administration, order: 104, @@ -59,7 +59,7 @@ export function configureRoutes() { requiredPolicy: eCmsKitAdminPolicyNames.BlogPosts, }, { - path: '/cms-kit/menus', + path: '/cms/menus', name: eCmsKitAdminRouteNames.Menus, parentName: eThemeSharedRouteNames.Administration, order: 105, @@ -68,7 +68,7 @@ export function configureRoutes() { requiredPolicy: eCmsKitAdminPolicyNames.Menus, }, { - path: '/cms-kit/global-resources', + path: '/cms/global-resources', name: eCmsKitAdminRouteNames.GlobalResources, parentName: eThemeSharedRouteNames.Administration, order: 106, diff --git a/npm/ng-packs/packages/cms-kit/admin/src/cms-kit-admin.routes.ts b/npm/ng-packs/packages/cms-kit/admin/src/cms-kit-admin.routes.ts index 31d1b884e5..78ed076c2e 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/cms-kit-admin.routes.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/cms-kit-admin.routes.ts @@ -7,10 +7,17 @@ import { ReplaceableRouteContainerComponent, } from '@abp/ng.core'; import { eCmsKitAdminComponents } from './enums'; - -export interface CmsKitAdminConfigOptions { - // Extension point contributors -} +import { + CommentListComponent, + CommentApproveComponent, + CommentDetailsComponent, +} from './components'; +import { + CMS_KIT_ADMIN_ENTITY_ACTION_CONTRIBUTORS, + CMS_KIT_ADMIN_ENTITY_PROP_CONTRIBUTORS, +} from './tokens'; +import { cmsKitAdminExtensionsResolver } from './resolvers'; +import { CmsKitAdminConfigOptions } from './models'; export function createRoutes(config: CmsKitAdminConfigOptions = {}): Routes { return [ @@ -20,7 +27,51 @@ export function createRoutes(config: CmsKitAdminConfigOptions = {}): Routes { providers: provideCmsKitAdminContributors(config), canActivate: [authGuard, permissionGuard], children: [ - // Routes will be added here + { + path: 'comments', + component: ReplaceableRouteContainerComponent, + resolve: { + extensions: cmsKitAdminExtensionsResolver, + }, + data: { + requiredPolicy: 'CmsKit.Comments', + replaceableComponent: { + key: eCmsKitAdminComponents.CommentList, + defaultComponent: CommentListComponent, + }, + }, + title: 'CmsKit::Comments', + }, + { + path: 'comments/approve', + component: ReplaceableRouteContainerComponent, + resolve: { + extensions: cmsKitAdminExtensionsResolver, + }, + data: { + requiredPolicy: 'CmsKit.Comments', + replaceableComponent: { + key: eCmsKitAdminComponents.CommentApprove, + defaultComponent: CommentApproveComponent, + }, + }, + title: 'CmsKit::Comments', + }, + { + path: 'comments/:id', + component: ReplaceableRouteContainerComponent, + resolve: { + extensions: cmsKitAdminExtensionsResolver, + }, + data: { + requiredPolicy: 'CmsKit.Comments', + replaceableComponent: { + key: eCmsKitAdminComponents.CommentDetails, + defaultComponent: CommentDetailsComponent, + }, + }, + title: 'CmsKit::Comments', + }, ], }, ]; @@ -28,6 +79,13 @@ export function createRoutes(config: CmsKitAdminConfigOptions = {}): Routes { function provideCmsKitAdminContributors(options: CmsKitAdminConfigOptions = {}): Provider[] { return [ - // Contributors will be added here + { + provide: CMS_KIT_ADMIN_ENTITY_ACTION_CONTRIBUTORS, + useValue: options.entityActionContributors, + }, + { + provide: CMS_KIT_ADMIN_ENTITY_PROP_CONTRIBUTORS, + useValue: options.entityPropContributors, + }, ]; } diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/comment-approve.component.html b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/comment-approve.component.html new file mode 100644 index 0000000000..26f182e763 --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/comment-approve.component.html @@ -0,0 +1,72 @@ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ +
+ +
+ +
+ +
+ +
+ + + +
+
+
+
+
+ +
+ +
+
diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/comment-approve.component.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/comment-approve.component.ts new file mode 100644 index 0000000000..645cc4db15 --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/comment-approve.component.ts @@ -0,0 +1,122 @@ +import { Component, OnInit, inject, LOCALE_ID } from '@angular/core'; +import { CommonModule, formatDate } from '@angular/common'; +import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; +import { ListService, LocalizationPipe, PagedResultDto } from '@abp/ng.core'; +import { ExtensibleTableComponent, EXTENSIONS_IDENTIFIER } from '@abp/ng.components/extensible'; +import { PageComponent } from '@abp/ng.components/page'; +import { ButtonComponent, FormInputComponent } from '@abp/ng.theme.shared'; +import { + CommentAdminService, + CommentGetListInput, + CommentWithAuthorDto, + CommentApproveState, +} from '@abp/ng.cms-kit/proxy'; +import { eCmsKitAdminComponents } from '../../../enums'; + +@Component({ + selector: 'abp-comment-approve', + templateUrl: './comment-approve.component.html', + providers: [ + ListService, + { + provide: EXTENSIONS_IDENTIFIER, + useValue: eCmsKitAdminComponents.CommentApprove, + }, + ], + imports: [ + ReactiveFormsModule, + NgbDatepickerModule, + CommonModule, + PageComponent, + ButtonComponent, + FormInputComponent, + LocalizationPipe, + ExtensibleTableComponent, + ], +}) +export class CommentApproveComponent implements OnInit { + data: PagedResultDto = { items: [], totalCount: 0 }; + + public readonly list = inject(ListService); + private commentService = inject(CommentAdminService); + private fb = inject(FormBuilder); + private locale = inject(LOCALE_ID); + + filterForm!: FormGroup; + + ngOnInit() { + this.createFilterForm(); + this.hookToQuery(); + } + + private createFilterForm() { + this.filterForm = this.fb.group({ + creationStartDate: [null], + creationEndDate: [null], + author: [''], + entityType: [''], + }); + } + + onFilter() { + const formValue = this.filterForm.value; + const filters: Partial = { + author: formValue.author || undefined, + entityType: formValue.entityType || undefined, + commentApproveState: CommentApproveState.Waiting, + }; + + if (formValue.creationStartDate) { + filters.creationStartDate = this.formatDateForApi(formValue.creationStartDate); + } + + if (formValue.creationEndDate) { + filters.creationEndDate = this.formatDateForApi(formValue.creationEndDate); + } + + this.list.filter = JSON.stringify(filters); + this.list.get(); + } + + private formatDateForApi(date: any): string { + if (!date) { + return ''; + } + + if (typeof date === 'string') { + return date; + } + + if (date.year && date.month && date.day) { + const jsDate = new Date(date.year, date.month - 1, date.day); + return formatDate(jsDate, 'yyyy-MM-dd', this.locale); + } + + return ''; + } + + private hookToQuery() { + this.list + .hookToQuery(query => { + let filters: Partial = { + commentApproveState: CommentApproveState.Waiting, + }; + if (this.list.filter) { + try { + filters = { ...filters, ...JSON.parse(this.list.filter) }; + } catch { + // Ignore parse errors, use default filters + } + } + 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/comments/comment-approve/index.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/index.ts new file mode 100644 index 0000000000..249ce54323 --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/index.ts @@ -0,0 +1 @@ +export * from './comment-approve.component'; 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 new file mode 100644 index 0000000000..aec95e36b8 --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.html @@ -0,0 +1,147 @@ + + @if (comment) { +
+
+ + + + + + + + + + + + + + + + + + @if (comment.repliedCommentId) { + + + + + } + + + + +
+ {{ 'CmsKit::EntityType' | abpLocalization }}: + {{ comment.entityType }}
+ {{ 'CmsKit::EntityId' | abpLocalization }}: + {{ comment.entityId }}
+ {{ 'AbpIdentity::CreationTime' | abpLocalization }}: + {{ comment.creationTime | date }}
+ {{ 'CmsKit::Username' | abpLocalization }}: + {{ comment.author?.name }}
+ {{ 'CmsKit::ReplyTo' | abpLocalization }}: + + + {{ comment.repliedCommentId }} + +
+ {{ 'CmsKit::Text' | abpLocalization }}: + {{ comment.text }}
+
+
+ } + +
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ +
+ +
+ + @if (requireApprovement) { +
+
+ + +
+
+ } + +
+
+ + + +
+
+
+
+
+
+ +

{{ '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 new file mode 100644 index 0000000000..4f753d433b --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.ts @@ -0,0 +1,152 @@ +import { Component, OnInit, inject, LOCALE_ID } from '@angular/core'; +import { CommonModule, DatePipe, formatDate } from '@angular/common'; +import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; +import { ListService, LocalizationPipe, PagedResultDto, ConfigStateService } from '@abp/ng.core'; +import { PageComponent } from '@abp/ng.components/page'; +import { ExtensibleTableComponent, EXTENSIONS_IDENTIFIER } from '@abp/ng.components/extensible'; +import { ButtonComponent, FormInputComponent } from '@abp/ng.theme.shared'; +import { + CommentAdminService, + CommentGetListInput, + CommentWithAuthorDto, + CommentApproveState, + commentApproveStateOptions, +} from '@abp/ng.cms-kit/proxy'; +import { eCmsKitAdminComponents } from '../../../enums'; +import { CMS_KIT_COMMENTS_REQUIRE_APPROVEMENT } from '../comment-list'; + +@Component({ + selector: 'abp-comment-details', + templateUrl: './comment-details.component.html', + providers: [ + ListService, + { + provide: EXTENSIONS_IDENTIFIER, + useValue: eCmsKitAdminComponents.CommentDetails, + }, + ], + imports: [ + ExtensibleTableComponent, + PageComponent, + LocalizationPipe, + ReactiveFormsModule, + NgbDatepickerModule, + CommonModule, + DatePipe, + FormInputComponent, + ButtonComponent, + ], +}) +export class CommentDetailsComponent implements OnInit { + comment: CommentWithAuthorDto | null = null; + data: PagedResultDto = { items: [], totalCount: 0 }; + + public readonly list = inject(ListService); + private commentService = inject(CommentAdminService); + private route = inject(ActivatedRoute); + private router = inject(Router); + private fb = inject(FormBuilder); + private configState = inject(ConfigStateService); + private locale = inject(LOCALE_ID); + + filterForm!: FormGroup; + commentApproveStateOptions = commentApproveStateOptions; + requireApprovement = false; + commentId!: string; + + ngOnInit() { + this.requireApprovement = + this.configState.getSetting(CMS_KIT_COMMENTS_REQUIRE_APPROVEMENT) === 'true'; + this.route.params.subscribe(params => { + const id = params['id']; + if (id) { + this.commentId = id; + this.loadComment(id); + this.createFilterForm(); + this.hookToQuery(); + } + }); + } + + private createFilterForm() { + this.filterForm = this.fb.group({ + creationStartDate: [null], + creationEndDate: [null], + author: [''], + commentApproveState: [CommentApproveState.All], + }); + } + + private loadComment(id: string) { + this.commentService.get(id).subscribe(comment => { + this.comment = comment; + }); + } + + onFilter() { + const formValue = this.filterForm.value; + const filters: Partial = { + author: formValue.author || undefined, + commentApproveState: formValue.commentApproveState, + repliedCommentId: this.commentId, + }; + + if (formValue.creationStartDate) { + filters.creationStartDate = this.formatDateForApi(formValue.creationStartDate); + } + + if (formValue.creationEndDate) { + filters.creationEndDate = this.formatDateForApi(formValue.creationEndDate); + } + + this.list.filter = JSON.stringify(filters); + this.list.get(); + } + + private formatDateForApi(date: any): string { + if (!date) { + return ''; + } + + if (typeof date === 'string') { + return date; + } + + if (date.year && date.month && date.day) { + const jsDate = new Date(date.year, date.month - 1, date.day); + return formatDate(jsDate, 'yyyy-MM-dd', this.locale); + } + + return ''; + } + + private hookToQuery() { + this.list + .hookToQuery(query => { + let filters: Partial = { + repliedCommentId: this.commentId, + }; + if (this.list.filter) { + try { + filters = { ...filters, ...JSON.parse(this.list.filter) }; + } catch { + // Ignore parse errors, use default filters + } + } + const input: CommentGetListInput = { + ...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-details/index.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/index.ts new file mode 100644 index 0000000000..8ba84ff6b7 --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/index.ts @@ -0,0 +1 @@ +export * from './comment-details.component'; 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 new file mode 100644 index 0000000000..2cba7cb433 --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.html @@ -0,0 +1,91 @@ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ +
+ +
+ +
+ +
+ @if (requireApprovement) { +
+
+ + +
+
+ } +
+ + + +
+
+
+
+
+ +
+ +
+
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 new file mode 100644 index 0000000000..b217b2f21a --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.ts @@ -0,0 +1,128 @@ +import { Component, OnInit, inject, LOCALE_ID } from '@angular/core'; +import { CommonModule, formatDate } from '@angular/common'; +import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; +import { ListService, PagedResultDto, ConfigStateService, LocalizationPipe } from '@abp/ng.core'; +import { ExtensibleModule, EXTENSIONS_IDENTIFIER } from '@abp/ng.components/extensible'; +import { PageModule } from '@abp/ng.components/page'; +import { ButtonComponent, FormInputComponent } from '@abp/ng.theme.shared'; +import { + CommentAdminService, + CommentGetListInput, + CommentWithAuthorDto, + CommentApproveState, + commentApproveStateOptions, +} from '@abp/ng.cms-kit/proxy'; +import { eCmsKitAdminComponents } from '../../../enums'; + +export const CMS_KIT_COMMENTS_REQUIRE_APPROVEMENT = 'CmsKit.Comments.RequireApprovement'; + +@Component({ + selector: 'abp-comment-list', + standalone: true, + templateUrl: './comment-list.component.html', + providers: [ + ListService, + { + provide: EXTENSIONS_IDENTIFIER, + useValue: eCmsKitAdminComponents.CommentList, + }, + ], + imports: [ + ExtensibleModule, + PageModule, + ReactiveFormsModule, + NgbDatepickerModule, + CommonModule, + LocalizationPipe, + FormInputComponent, + ButtonComponent, + ], +}) +export class CommentListComponent implements OnInit { + data: PagedResultDto = { items: [], totalCount: 0 }; + + public readonly list = inject(ListService); + private commentService = inject(CommentAdminService); + private fb = inject(FormBuilder); + private configState = inject(ConfigStateService); + private locale = inject(LOCALE_ID); + + filterForm!: FormGroup; + commentApproveStateOptions = commentApproveStateOptions; + requireApprovement = false; + + ngOnInit() { + this.requireApprovement = + this.configState.getSetting(CMS_KIT_COMMENTS_REQUIRE_APPROVEMENT) === 'true'; + this.createFilterForm(); + this.hookToQuery(); + } + + private createFilterForm() { + this.filterForm = this.fb.group({ + creationStartDate: [null], + creationEndDate: [null], + author: [''], + entityType: [''], + commentApproveState: [CommentApproveState.All], + }); + } + + onFilter() { + const formValue = this.filterForm.value; + const filters: Partial = { + author: formValue.author || undefined, + entityType: formValue.entityType || undefined, + commentApproveState: formValue.commentApproveState, + }; + + if (formValue.creationStartDate) { + filters.creationStartDate = this.formatDateForApi(formValue.creationStartDate); + } + + if (formValue.creationEndDate) { + filters.creationEndDate = this.formatDateForApi(formValue.creationEndDate); + } + + this.list.filter = JSON.stringify(filters); + this.list.get(); + } + + private formatDateForApi(date: any): string { + if (!date) { + return ''; + } + + if (typeof date === 'string') { + return date; + } + + if (date.year && date.month && date.day) { + const jsDate = new Date(date.year, date.month - 1, date.day); + return formatDate(jsDate, 'yyyy-MM-dd', this.locale); + } + + return ''; + } + + private hookToQuery() { + this.list + .hookToQuery(query => { + let filters: Partial = {}; + if (this.list.filter) { + try { + filters = JSON.parse(this.list.filter); + } catch { + // Ignore parse errors, use empty filters + } + } + 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/comments/comment-list/index.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/index.ts new file mode 100644 index 0000000000..4f9264de92 --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/index.ts @@ -0,0 +1 @@ +export * from './comment-list.component'; diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/comments/index.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/index.ts new file mode 100644 index 0000000000..3858cb3dc4 --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/comments/index.ts @@ -0,0 +1,3 @@ +export * from './comment-list'; +export * from './comment-approve'; +export * from './comment-details'; diff --git a/npm/ng-packs/packages/cms-kit/admin/src/components/index.ts b/npm/ng-packs/packages/cms-kit/admin/src/components/index.ts index 4173f31c58..59772e9b42 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/components/index.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/components/index.ts @@ -1,5 +1,4 @@ -// Components will be exported here -// export * from './comments'; +export * from './comments'; // export * from './tags'; // export * from './pages'; // export * from './blogs'; diff --git a/npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/default-comment-entity-actions.ts b/npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/default-comment-entity-actions.ts new file mode 100644 index 0000000000..7062a80d5a --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/default-comment-entity-actions.ts @@ -0,0 +1,62 @@ +import { CommentWithAuthorDto } from '@abp/ng.cms-kit/proxy'; +import { EntityAction } from '@abp/ng.components/extensible'; +import { Router } from '@angular/router'; +import { CommentAdminService } from '@abp/ng.cms-kit/proxy'; +import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared'; +import { ConfigStateService, ListService } from '@abp/ng.core'; + +export const DEFAULT_COMMENT_ENTITY_ACTIONS = EntityAction.createMany([ + { + text: 'CmsKit::Details', + action: data => { + const router = data.getInjected(Router); + router.navigate(['/cms/comments', data.record.id]); + }, + }, + { + text: 'CmsKit::Delete', + action: data => { + const commentService = data.getInjected(CommentAdminService); + const confirmation = data.getInjected(ConfirmationService); + const list = data.getInjected(ListService); + + confirmation + .warn('CmsKit::CommentDeletionConfirmationMessage', 'AbpUi::AreYouSure', { + yesText: 'AbpUi::Yes', + cancelText: 'AbpUi::Cancel', + }) + .subscribe(status => { + if (status === Confirmation.Status.confirm) { + commentService.delete(data.record.id!).subscribe(() => { + list.get(); + }); + } + }); + }, + permission: 'CmsKit.Comments.Delete', + }, + { + // text: data => { + // return data.record.isApproved ? 'CmsKit::Disapproved' : 'CmsKit::Approve'; + // }, + // TODO: Add a resolver for the text + text: 'CmsKit::Approve', + action: data => { + const commentService = data.getInjected(CommentAdminService); + const list = data.getInjected(ListService); + const newApprovalStatus = !data.record.isApproved; + + commentService + .updateApprovalStatus(data.record.id!, { isApproved: newApprovalStatus }) + .subscribe(() => { + list.get(); + }); + }, + visible: data => { + const configState = data.getInjected(ConfigStateService); + const requireApprovement = + configState.getSetting('CmsKit.Comments.RequireApprovement') === 'true'; + return requireApprovement; + }, + }, +]); diff --git a/npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/default-comment-entity-props.ts b/npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/default-comment-entity-props.ts new file mode 100644 index 0000000000..ba08af6cf7 --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/default-comment-entity-props.ts @@ -0,0 +1,78 @@ +import { CommentWithAuthorDto } from '@abp/ng.cms-kit/proxy'; +import { EntityProp, ePropType } from '@abp/ng.components/extensible'; +import { ConfigStateService } from '@abp/ng.core'; +import { of } from 'rxjs'; + +export const DEFAULT_COMMENT_ENTITY_PROPS = EntityProp.createMany([ + { + type: ePropType.String, + name: 'author.userName', + displayName: 'CmsKit::Username', + sortable: false, + columnWidth: 150, + }, + { + type: ePropType.String, + name: 'entityType', + displayName: 'CmsKit::EntityType', + sortable: false, + columnWidth: 200, + }, + { + type: ePropType.String, + name: 'url', + displayName: 'CmsKit::URL', + sortable: false, + valueResolver: data => { + const url = data.record.url; + if (url) { + return of( + ``, + ); + } + return of(''); + }, + }, + { + type: ePropType.String, + name: 'text', + displayName: 'CmsKit::Text', + sortable: false, + valueResolver: data => { + const text = data.record.text || ''; + const maxChars = 64; + if (text.length > maxChars) { + return of(text.substring(0, maxChars) + '...'); + } + return of(text); + }, + }, + { + type: ePropType.Boolean, + name: 'isApproved', + displayName: 'CmsKit::ApproveState', + sortable: false, + columnWidth: 100, + columnVisible: getInjected => { + const configState = getInjected(ConfigStateService); + return configState.getSetting('CmsKit.Comments.RequireApprovement') === 'true'; + }, + valueResolver: data => { + const isApproved = data.record.isApproved; + if (isApproved === null || isApproved === undefined) { + return of(''); + } else if (isApproved === true) { + return of(''); + } else { + return of(''); + } + }, + }, + { + type: ePropType.Date, + name: 'creationTime', + displayName: 'AbpIdentity::CreationTime', + sortable: true, + columnWidth: 200, + }, +]); diff --git a/npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/index.ts b/npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/index.ts new file mode 100644 index 0000000000..48599b1647 --- /dev/null +++ b/npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/index.ts @@ -0,0 +1,2 @@ +export * from './default-comment-entity-actions'; +export * from './default-comment-entity-props'; diff --git a/npm/ng-packs/packages/cms-kit/admin/src/defaults/index.ts b/npm/ng-packs/packages/cms-kit/admin/src/defaults/index.ts index e69de29bb2..9ec22c6f8c 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/defaults/index.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/defaults/index.ts @@ -0,0 +1 @@ +export * from './comments'; diff --git a/npm/ng-packs/packages/cms-kit/admin/src/models/config-options.ts b/npm/ng-packs/packages/cms-kit/admin/src/models/config-options.ts index 8b2584bb68..5f8a5b0ced 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/models/config-options.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/models/config-options.ts @@ -1,3 +1,29 @@ +import { eCmsKitAdminComponents } from '../enums'; +import { + EntityActionContributorCallback, + EntityPropContributorCallback, +} from '@abp/ng.components/extensible'; +import { CommentWithAuthorDto } from '@abp/ng.cms-kit/proxy'; + +export type CmsKitAdminEntityActionContributors = Partial<{ + [eCmsKitAdminComponents.CommentList]: EntityActionContributorCallback[]; + [eCmsKitAdminComponents.CommentApprove]: EntityActionContributorCallback[]; + [eCmsKitAdminComponents.CommentDetails]: EntityActionContributorCallback[]; +}>; + +export type CmsKitAdminEntityPropContributors = Partial<{ + [eCmsKitAdminComponents.CommentList]: EntityPropContributorCallback[]; + [eCmsKitAdminComponents.CommentApprove]: EntityPropContributorCallback[]; + [eCmsKitAdminComponents.CommentDetails]: EntityPropContributorCallback[]; +}>; + +export type CmsKitAdminCreateFormPropContributors = Partial<{}>; + +export type CmsKitAdminEditFormPropContributors = Partial<{}>; + export interface CmsKitAdminConfigOptions { - // Extension point contributors will be added here + entityActionContributors?: CmsKitAdminEntityActionContributors; + entityPropContributors?: CmsKitAdminEntityPropContributors; + createFormPropContributors?: CmsKitAdminCreateFormPropContributors; + editFormPropContributors?: CmsKitAdminEditFormPropContributors; } diff --git a/npm/ng-packs/packages/cms-kit/admin/src/public-api.ts b/npm/ng-packs/packages/cms-kit/admin/src/public-api.ts index 01b1709e8f..419d0f94eb 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/public-api.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/public-api.ts @@ -1,8 +1,6 @@ -// export * from './components'; -// export * from './defaults'; +export * from './components'; +export * from './defaults'; export * from './enums'; -// export * from './models'; export * from './resolvers'; -// export * from './services'; export * from './tokens'; export * from './cms-kit-admin.routes'; diff --git a/npm/ng-packs/packages/cms-kit/admin/src/resolvers/extensions.resolver.ts b/npm/ng-packs/packages/cms-kit/admin/src/resolvers/extensions.resolver.ts index bcd300ab62..a06a96f399 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/resolvers/extensions.resolver.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/resolvers/extensions.resolver.ts @@ -1,8 +1,49 @@ +import { + ExtensionsService, + getObjectExtensionEntitiesFromStore, + mapEntitiesToContributors, + mergeWithDefaultActions, + mergeWithDefaultProps, +} from '@abp/ng.components/extensible'; +import { inject, Injector } from '@angular/core'; import { ResolveFn } from '@angular/router'; +import { map, tap } from 'rxjs'; +import { eCmsKitAdminComponents } from '../enums'; +import { + CMS_KIT_ADMIN_ENTITY_ACTION_CONTRIBUTORS, + CMS_KIT_ADMIN_ENTITY_PROP_CONTRIBUTORS, + DEFAULT_CMS_KIT_ADMIN_ENTITY_ACTIONS, + DEFAULT_CMS_KIT_ADMIN_ENTITY_PROPS, +} from '../tokens'; -// Resolvers will be defined here -// Example: -// export const cmsKitAdminResolver: ResolveFn = (route, state) => { -// // Resolver implementation -// return null; -// }; +export const cmsKitAdminExtensionsResolver: ResolveFn = () => { + const injector = inject(Injector); + const extensions = inject(ExtensionsService); + + const config = { optional: true }; + + const actionContributors = inject(CMS_KIT_ADMIN_ENTITY_ACTION_CONTRIBUTORS, config) || {}; + const propContributors = inject(CMS_KIT_ADMIN_ENTITY_PROP_CONTRIBUTORS, config) || {}; + + return getObjectExtensionEntitiesFromStore(injector, 'CmsKit').pipe( + map(entities => ({ + [eCmsKitAdminComponents.CommentList]: entities.Comment, + [eCmsKitAdminComponents.CommentApprove]: entities.Comment, + [eCmsKitAdminComponents.CommentDetails]: entities.Comment, + })), + mapEntitiesToContributors(injector, 'CmsKit'), + tap(objectExtensionContributors => { + mergeWithDefaultActions( + extensions.entityActions, + DEFAULT_CMS_KIT_ADMIN_ENTITY_ACTIONS, + actionContributors, + ); + mergeWithDefaultProps( + extensions.entityProps, + DEFAULT_CMS_KIT_ADMIN_ENTITY_PROPS, + objectExtensionContributors.prop, + propContributors, + ); + }), + ); +}; diff --git a/npm/ng-packs/packages/cms-kit/admin/src/tokens/extensions.token.ts b/npm/ng-packs/packages/cms-kit/admin/src/tokens/extensions.token.ts index 2887603976..0db46e740c 100644 --- a/npm/ng-packs/packages/cms-kit/admin/src/tokens/extensions.token.ts +++ b/npm/ng-packs/packages/cms-kit/admin/src/tokens/extensions.token.ts @@ -1,4 +1,41 @@ +import { CommentWithAuthorDto } from '@abp/ng.cms-kit/proxy'; +import { + EntityActionContributorCallback, + EntityPropContributorCallback, +} from '@abp/ng.components/extensible'; import { InjectionToken } from '@angular/core'; +import { DEFAULT_COMMENT_ENTITY_ACTIONS } from '../defaults/comments/default-comment-entity-actions'; +import { DEFAULT_COMMENT_ENTITY_PROPS } from '../defaults/comments/default-comment-entity-props'; +import { eCmsKitAdminComponents } from '../enums'; -// Extension tokens will be defined here -export const EXTENSIONS_IDENTIFIER = new InjectionToken('EXTENSIONS_IDENTIFIER'); +export const DEFAULT_CMS_KIT_ADMIN_ENTITY_ACTIONS = { + [eCmsKitAdminComponents.CommentList]: DEFAULT_COMMENT_ENTITY_ACTIONS, + [eCmsKitAdminComponents.CommentApprove]: DEFAULT_COMMENT_ENTITY_ACTIONS, + [eCmsKitAdminComponents.CommentDetails]: DEFAULT_COMMENT_ENTITY_ACTIONS, +}; + +export const DEFAULT_CMS_KIT_ADMIN_ENTITY_PROPS = { + [eCmsKitAdminComponents.CommentList]: DEFAULT_COMMENT_ENTITY_PROPS, + [eCmsKitAdminComponents.CommentApprove]: DEFAULT_COMMENT_ENTITY_PROPS, + [eCmsKitAdminComponents.CommentDetails]: DEFAULT_COMMENT_ENTITY_PROPS, +}; + +export const CMS_KIT_ADMIN_ENTITY_ACTION_CONTRIBUTORS = + new InjectionToken('CMS_KIT_ADMIN_ENTITY_ACTION_CONTRIBUTORS'); + +export const CMS_KIT_ADMIN_ENTITY_PROP_CONTRIBUTORS = new InjectionToken( + 'CMS_KIT_ADMIN_ENTITY_PROP_CONTRIBUTORS', +); + +// Fix for TS4023 -> https://github.com/microsoft/TypeScript/issues/9944#issuecomment-254693497 +type EntityActionContributors = Partial<{ + [eCmsKitAdminComponents.CommentList]: EntityActionContributorCallback[]; + [eCmsKitAdminComponents.CommentApprove]: EntityActionContributorCallback[]; + [eCmsKitAdminComponents.CommentDetails]: EntityActionContributorCallback[]; +}>; + +type EntityPropContributors = Partial<{ + [eCmsKitAdminComponents.CommentList]: EntityPropContributorCallback[]; + [eCmsKitAdminComponents.CommentApprove]: EntityPropContributorCallback[]; + [eCmsKitAdminComponents.CommentDetails]: EntityPropContributorCallback[]; +}>;