Browse Source

add: comments feature for the cms kit admin side

pull/24234/head
sumeyye 10 months ago
parent
commit
67ed01ee3f
  1. 2
      npm/ng-packs/packages/cms-kit/admin/config/src/enums/route-names.ts
  2. 2
      npm/ng-packs/packages/cms-kit/admin/config/src/providers/cms-kit-admin-config.provider.ts
  3. 16
      npm/ng-packs/packages/cms-kit/admin/config/src/providers/route.provider.ts
  4. 70
      npm/ng-packs/packages/cms-kit/admin/src/cms-kit-admin.routes.ts
  5. 72
      npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/comment-approve.component.html
  6. 122
      npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/comment-approve.component.ts
  7. 1
      npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/index.ts
  8. 147
      npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.html
  9. 152
      npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.ts
  10. 1
      npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/index.ts
  11. 91
      npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.html
  12. 128
      npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.ts
  13. 1
      npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/index.ts
  14. 3
      npm/ng-packs/packages/cms-kit/admin/src/components/comments/index.ts
  15. 3
      npm/ng-packs/packages/cms-kit/admin/src/components/index.ts
  16. 62
      npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/default-comment-entity-actions.ts
  17. 78
      npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/default-comment-entity-props.ts
  18. 2
      npm/ng-packs/packages/cms-kit/admin/src/defaults/comments/index.ts
  19. 1
      npm/ng-packs/packages/cms-kit/admin/src/defaults/index.ts
  20. 28
      npm/ng-packs/packages/cms-kit/admin/src/models/config-options.ts
  21. 6
      npm/ng-packs/packages/cms-kit/admin/src/public-api.ts
  22. 53
      npm/ng-packs/packages/cms-kit/admin/src/resolvers/extensions.resolver.ts
  23. 41
      npm/ng-packs/packages/cms-kit/admin/src/tokens/extensions.token.ts

2
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',

2
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() {

16
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,

70
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,
},
];
}

72
npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/comment-approve.component.html

@ -0,0 +1,72 @@
<abp-page [title]="'CmsKit::Comments' | abpLocalization">
<div class="card mb-4">
<div class="card-body">
<form [formGroup]="filterForm" (ngSubmit)="onFilter()">
<div class="row align-items-end">
<div class="col-lg-4 col-md-12">
<div class="row">
<div class="col-lg-6 col-md-6">
<div class="mb-3">
<label class="form-label" for="creationStartDate">
{{ 'CmsKit::StartDate' | abpLocalization }}
</label>
<input
id="creationStartDate"
formControlName="creationStartDate"
class="form-control"
ngbDatepicker
#startDatePicker="ngbDatepicker"
(click)="startDatePicker.toggle()"
readonly
/>
</div>
</div>
<div class="col-lg-6 col-md-6">
<div class="mb-3">
<label class="form-label" for="creationEndDate">
{{ 'CmsKit::EndDate' | abpLocalization }}
</label>
<input
id="creationEndDate"
formControlName="creationEndDate"
class="form-control"
ngbDatepicker
#endDatePicker="ngbDatepicker"
(click)="endDatePicker.toggle()"
readonly
/>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<abp-form-input
formControlName="author"
[label]="'CmsKit::Username' | abpLocalization"
type="text"
/>
</div>
<div class="col-lg-3 col-md-6">
<abp-form-input
formControlName="entityType"
[label]="'CmsKit::EntityType' | abpLocalization"
type="text"
/>
</div>
<div class="col-lg-2 col-md-6">
<abp-button class="w-100 mb-3" buttonType="Primary" type="submit">
<i class="fa fa-search" aria-hidden="true"></i>
</abp-button>
</div>
</div>
</form>
</div>
</div>
<div class="card">
<abp-extensible-table [data]="data.items" [recordsTotal]="data.totalCount" [list]="list" />
</div>
</abp-page>

122
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<CommentWithAuthorDto> = { items: [], totalCount: 0 };
public readonly list = inject(ListService<CommentGetListInput>);
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<CommentGetListInput> = {
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<CommentGetListInput> = {
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;
});
}
}

1
npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-approve/index.ts

@ -0,0 +1 @@
export * from './comment-approve.component';

147
npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/comment-details.component.html

@ -0,0 +1,147 @@
<abp-page [title]="'CmsKit::Comments' | abpLocalization">
@if (comment) {
<div class="card mb-4">
<div class="card-body">
<table class="table">
<tr>
<td width="10%">
<b>{{ 'CmsKit::EntityType' | abpLocalization }}</b
>:
</td>
<td>{{ comment.entityType }}</td>
</tr>
<tr>
<td>
<b>{{ 'CmsKit::EntityId' | abpLocalization }}</b
>:
</td>
<td>{{ comment.entityId }}</td>
</tr>
<tr>
<td>
<b>{{ 'AbpIdentity::CreationTime' | abpLocalization }}</b
>:
</td>
<td>{{ comment.creationTime | date }}</td>
</tr>
<tr>
<td>
<b>{{ 'CmsKit::Username' | abpLocalization }}</b
>:
</td>
<td>{{ comment.author?.name }}</td>
</tr>
@if (comment.repliedCommentId) {
<tr>
<td>
<b>{{ 'CmsKit::ReplyTo' | abpLocalization }}</b
>:
</td>
<td>
<a (click)="navigateToReply(comment.repliedCommentId!)" style="cursor: pointer">
{{ comment.repliedCommentId }}
</a>
</td>
</tr>
}
<tr>
<td class="align-text-top">
<b>{{ 'CmsKit::Text' | abpLocalization }}</b
>:
</td>
<td>{{ comment.text }}</td>
</tr>
</table>
</div>
</div>
}
<div class="card mb-4">
<div class="card-body">
<form [formGroup]="filterForm" (ngSubmit)="onFilter()">
<input type="hidden" [value]="commentId" />
<div class="row">
<div class="col-lg-4 col-md-12">
<div class="row">
<div class="col-lg-6 col-md-6">
<div class="mb-3">
<label class="form-label" for="creationStartDate">
{{ 'CmsKit::StartDate' | abpLocalization }}
</label>
<input
id="creationStartDate"
formControlName="creationStartDate"
class="form-control"
ngbDatepicker
#startDatePicker="ngbDatepicker"
(click)="startDatePicker.toggle()"
readonly
/>
</div>
</div>
<div class="col-lg-6 col-md-6">
<div class="mb-3">
<label class="form-label" for="creationEndDate">
{{ 'CmsKit::EndDate' | abpLocalization }}
</label>
<input
id="creationEndDate"
formControlName="creationEndDate"
class="form-control"
ngbDatepicker
#endDatePicker="ngbDatepicker"
(click)="endDatePicker.toggle()"
readonly
/>
</div>
</div>
</div>
</div>
<div class="col-lg-4 col-md-12">
<abp-form-input
formControlName="author"
[label]="'CmsKit::Username' | abpLocalization"
type="text"
/>
</div>
@if (requireApprovement) {
<div class="col-lg-2 col-md-12">
<div class="mb-3">
<label class="mb-1 form-label" for="commentApproveState">
{{ 'CmsKit::CommentFilter:ApproveState' | abpLocalization }}
</label>
<select
id="commentApproveState"
formControlName="commentApproveState"
class="form-control"
>
@for (option of commentApproveStateOptions; track option.value) {
<option [value]="option.value">
{{ 'CmsKit::CommentFilter:' + option.value | abpLocalization }}
</option>
}
</select>
</div>
</div>
}
<div class="col-lg-2 col-md-12">
<div class="d-grid gap-2">
<abp-button class="mt-md-4" buttonType="Primary" type="submit">
<i class="fa fa-search" aria-hidden="true"></i>
</abp-button>
</div>
</div>
</div>
</form>
</div>
</div>
<h3>{{ 'CmsKit::RepliesToThisComment' | abpLocalization }}</h3>
<div class="card">
<abp-extensible-table [data]="data.items" [recordsTotal]="data.totalCount" [list]="list" />
</div>
</abp-page>

152
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<CommentWithAuthorDto> = { items: [], totalCount: 0 };
public readonly list = inject(ListService<CommentGetListInput>);
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<CommentGetListInput> = {
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<CommentGetListInput> = {
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]);
}
}

1
npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-details/index.ts

@ -0,0 +1 @@
export * from './comment-details.component';

91
npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/comment-list.component.html

@ -0,0 +1,91 @@
<abp-page [title]="'CmsKit::Comments' | abpLocalization">
<div class="card mb-4">
<div class="card-body">
<form [formGroup]="filterForm" (ngSubmit)="onFilter()">
<div class="row align-items-end">
<div class="col-lg-4 col-md-12">
<div class="row">
<div class="col-lg-6 col-md-6">
<div class="mb-3">
<label class="form-label" for="creationStartDate">
{{ 'CmsKit::StartDate' | abpLocalization }}
</label>
<input
id="creationStartDate"
formControlName="creationStartDate"
class="form-control"
ngbDatepicker
#startDatePicker="ngbDatepicker"
(click)="startDatePicker.toggle()"
readonly
/>
</div>
</div>
<div class="col-lg-6 col-md-6">
<div class="mb-3">
<label class="form-label" for="creationEndDate">
{{ 'CmsKit::EndDate' | abpLocalization }}
</label>
<input
id="creationEndDate"
formControlName="creationEndDate"
class="form-control"
ngbDatepicker
#endDatePicker="ngbDatepicker"
(click)="endDatePicker.toggle()"
readonly
/>
</div>
</div>
</div>
</div>
<div class="col-lg-2 col-md-6">
<abp-form-input
formControlName="author"
[label]="'CmsKit::Username' | abpLocalization"
type="text"
/>
</div>
<div class="col-lg-2 col-md-6">
<abp-form-input
formControlName="entityType"
[label]="'CmsKit::EntityType' | abpLocalization"
type="text"
/>
</div>
@if (requireApprovement) {
<div class="col-lg-2 col-md-6">
<div class="mb-3">
<label class="mb-1 form-label" for="commentApproveState">
{{ 'CmsKit::CommentFilter:ApproveState' | abpLocalization }}
</label>
<select
id="commentApproveState"
formControlName="commentApproveState"
class="form-control"
>
@for (option of commentApproveStateOptions; track option.value) {
<option [value]="option.value">
{{ 'CmsKit::CommentFilter:' + option.value | abpLocalization }}
</option>
}
</select>
</div>
</div>
}
<div class="col-lg-2 col-md-6">
<abp-button class="w-100 mb-3" buttonType="Primary" type="submit">
<i class="fa fa-search" aria-hidden="true"></i>
</abp-button>
</div>
</div>
</form>
</div>
</div>
<div class="card">
<abp-extensible-table [data]="data.items" [recordsTotal]="data.totalCount" [list]="list" />
</div>
</abp-page>

128
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<CommentWithAuthorDto> = { items: [], totalCount: 0 };
public readonly list = inject(ListService<CommentGetListInput>);
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<CommentGetListInput> = {
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<CommentGetListInput> = {};
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));
}
}

1
npm/ng-packs/packages/cms-kit/admin/src/components/comments/comment-list/index.ts

@ -0,0 +1 @@
export * from './comment-list.component';

3
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';

3
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';

62
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<CommentWithAuthorDto>([
{
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;
},
},
]);

78
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<CommentWithAuthorDto>([
{
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(
`<a href="${url}#comment-${data.record.id}" target="_blank"><i class="fa fa-location-arrow"></i></a>`,
);
}
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('<i class="fa-solid fa-hourglass-half text-muted"></i>');
} else if (isApproved === true) {
return of('<i class="fa-solid fa-check text-success"></i>');
} else {
return of('<i class="fa-solid fa-x text-danger"></i>');
}
},
},
{
type: ePropType.Date,
name: 'creationTime',
displayName: 'AbpIdentity::CreationTime',
sortable: true,
columnWidth: 200,
},
]);

2
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';

1
npm/ng-packs/packages/cms-kit/admin/src/defaults/index.ts

@ -0,0 +1 @@
export * from './comments';

28
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<CommentWithAuthorDto>[];
[eCmsKitAdminComponents.CommentApprove]: EntityActionContributorCallback<CommentWithAuthorDto>[];
[eCmsKitAdminComponents.CommentDetails]: EntityActionContributorCallback<CommentWithAuthorDto>[];
}>;
export type CmsKitAdminEntityPropContributors = Partial<{
[eCmsKitAdminComponents.CommentList]: EntityPropContributorCallback<CommentWithAuthorDto>[];
[eCmsKitAdminComponents.CommentApprove]: EntityPropContributorCallback<CommentWithAuthorDto>[];
[eCmsKitAdminComponents.CommentDetails]: EntityPropContributorCallback<CommentWithAuthorDto>[];
}>;
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;
}

6
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';

53
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<any> = (route, state) => {
// // Resolver implementation
// return null;
// };
export const cmsKitAdminExtensionsResolver: ResolveFn<any> = () => {
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,
);
}),
);
};

41
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<string>('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<EntityActionContributors>('CMS_KIT_ADMIN_ENTITY_ACTION_CONTRIBUTORS');
export const CMS_KIT_ADMIN_ENTITY_PROP_CONTRIBUTORS = new InjectionToken<EntityPropContributors>(
'CMS_KIT_ADMIN_ENTITY_PROP_CONTRIBUTORS',
);
// Fix for TS4023 -> https://github.com/microsoft/TypeScript/issues/9944#issuecomment-254693497
type EntityActionContributors = Partial<{
[eCmsKitAdminComponents.CommentList]: EntityActionContributorCallback<CommentWithAuthorDto>[];
[eCmsKitAdminComponents.CommentApprove]: EntityActionContributorCallback<CommentWithAuthorDto>[];
[eCmsKitAdminComponents.CommentDetails]: EntityActionContributorCallback<CommentWithAuthorDto>[];
}>;
type EntityPropContributors = Partial<{
[eCmsKitAdminComponents.CommentList]: EntityPropContributorCallback<CommentWithAuthorDto>[];
[eCmsKitAdminComponents.CommentApprove]: EntityPropContributorCallback<CommentWithAuthorDto>[];
[eCmsKitAdminComponents.CommentDetails]: EntityPropContributorCallback<CommentWithAuthorDto>[];
}>;

Loading…
Cancel
Save