Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Angular - Implementing the CMS Kit module features#24234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
sumeyyeKurtulus wants to merge18 commits intodev
base:dev
Choose a base branch
Loading
fromissue/cms-kit-angular
Draft
Show file tree
Hide file tree
Changes from1 commit
Commits
Show all changes
18 commits
Select commitHold shift + click to select a range
104dcb8
update: add guides
sumeyyeKurtulusNov 17, 2025
10469d4
add: cms kit library skeleton
sumeyyeKurtulusNov 17, 2025
175e64e
add: cms kit library proxy
sumeyyeKurtulusNov 17, 2025
89d4d7c
add: cms kit library path declarations
sumeyyeKurtulusNov 17, 2025
ead7d06
update: proxy imports
sumeyyeKurtulusNov 17, 2025
dff20ff
fix: guides
sumeyyeKurtulusNov 17, 2025
67ed01e
add: comments feature for the cms kit admin side
sumeyyeKurtulusNov 17, 2025
9f909aa
add: tags for the admin side
sumeyyeKurtulusNov 18, 2025
6717280
add: pages structure
sumeyyeKurtulusNov 19, 2025
0c65999
add: common code mirror and toast ui components
sumeyyeKurtulusNov 19, 2025
2e61b5d
update: route names for the admin cms kit
sumeyyeKurtulusNov 19, 2025
3b33b62
add: `@toast-ui/editor` and `codemirror` dependencies
sumeyyeKurtulusNov 19, 2025
138742c
add: blogs structure for the admin side
sumeyyeKurtulusNov 19, 2025
2704848
add: utils for the cms kit operations
sumeyyeKurtulusNov 19, 2025
b26b686
add: blog posts feature for the admin side
sumeyyeKurtulusNov 19, 2025
363fdf4
update: add cover image and tags
sumeyyeKurtulusNov 19, 2025
64fcb11
add: menu items for the admin side
sumeyyeKurtulusNov 19, 2025
3c587b2
fix: menu item modal component problems
sumeyyeKurtulusNov 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
NextNext commit
add: blog posts feature for the admin side
  • Loading branch information
@sumeyyeKurtulus
sumeyyeKurtulus committedNov 19, 2025
commitb26b68613fe774ae019f08d3e5233211dca96c6a
12 changes: 6 additions & 6 deletionsnpm/ng-packs/guides/CMS_KIT_ANGULAR_STRUCTURE.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1203,15 +1203,15 @@ export enum eCmsKitAdminRouteNames {

### Phase 5: Admin - Blogs Feature

- [] Create Blog components
- [] Create default extension points
- [] Add routes and providers
- [x] Create Blog components
- [x] Create default extension points
- [x] Add routes and providers

### Phase 6: Admin - Blog Posts Feature

- [] Create BlogPost components
- [] Create default extension points
- [] Add routes and providers
- [x] Create BlogPost components
- [x] Create default extension points
- [x] Add routes and providers

### Phase 7: Admin - Menus Feature

Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,8 @@ import {
PageListComponent,
PageFormComponent,
BlogListComponent,
BlogPostListComponent,
BlogPostFormComponent,
} from './components';
import {
CMS_KIT_ADMIN_ENTITY_ACTION_CONTRIBUTORS,
Expand DownExpand Up@@ -154,6 +156,51 @@ export function createRoutes(config: CmsKitAdminConfigOptions = {}): Routes {
},
title: 'CmsKit::Blogs',
},
{
path: 'blog-posts',
component: ReplaceableRouteContainerComponent,
resolve: {
extensions: cmsKitAdminExtensionsResolver,
},
data: {
requiredPolicy: 'CmsKit.BlogPosts',
replaceableComponent: {
key: eCmsKitAdminComponents.BlogPosts,
defaultComponent: BlogPostListComponent,
},
},
title: 'CmsKit::BlogPosts',
},
{
path: 'blog-posts/create',
component: ReplaceableRouteContainerComponent,
resolve: {
extensions: cmsKitAdminExtensionsResolver,
},
data: {
requiredPolicy: 'CmsKit.BlogPosts.Create',
replaceableComponent: {
key: eCmsKitAdminComponents.BlogPostForm,
defaultComponent: BlogPostFormComponent,
},
},
title: 'CmsKit::BlogPosts',
},
{
path: 'blog-posts/update/:id',
component: ReplaceableRouteContainerComponent,
resolve: {
extensions: cmsKitAdminExtensionsResolver,
},
data: {
requiredPolicy: 'CmsKit.BlogPosts.Update',
replaceableComponent: {
key: eCmsKitAdminComponents.BlogPostForm,
defaultComponent: BlogPostFormComponent,
},
},
title: 'CmsKit::BlogPosts',
},
],
},
];
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
<abp-page [title]="'CmsKit::BlogPosts' | abpLocalization">
<div class="card">
<div class="card-body">
@if (form && (!isEditMode || blogPost)) {
<form [formGroup]="form" (ngSubmit)="saveAsDraft()" validateOnSubmit>
<!-- Basic fields -->
<abp-extensible-form [selectedRecord]="blogPost || {}" />

<!-- Content editor -->
<div class="mt-3">
<label class="form-label">{{ 'CmsKit::Content' | abpLocalization }}</label>
<abp-toastui-editor formControlName="content" />
</div>
</form>
} @else {
<div class="text-center">
<i class="fa fa-pulse fa-spinner" aria-hidden="true"></i>
</div>
}
</div>
<div class="card-footer">
<div class="d-flex justify-content-start gap-2">
<button class="btn btn-secondary" (click)="saveAsDraft()" [disabled]="form?.invalid">
{{ 'CmsKit::SaveAsDraft' | abpLocalization }}
</button>
@if (isEditMode) {
<abp-button (click)="publish()" [disabled]="form?.invalid">
{{ 'CmsKit::Publish' | abpLocalization }}
</abp-button>
} @else {
<abp-button (click)="publish()" [disabled]="form?.invalid">
{{ 'CmsKit::Publish' | abpLocalization }}
</abp-button>
<abp-button (click)="sendToReview()" [disabled]="form?.invalid">
{{ 'CmsKit::SendToReviewToPublish' | abpLocalization }}
</abp-button>
}
</div>
</div>
</div>
</abp-page>
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
import { Component, OnInit, inject, Injector, DestroyRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule, FormGroup, FormControl } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { NgxValidateCoreModule } from '@ngx-validate/core';
import { LocalizationPipe } from '@abp/ng.core';
import {
ExtensibleFormComponent,
FormPropData,
generateFormFromProps,
EXTENSIONS_IDENTIFIER,
} from '@abp/ng.components/extensible';
import { PageComponent } from '@abp/ng.components/page';
import { ButtonComponent } from '@abp/ng.theme.shared';
import { ToastuiEditorComponent, prepareSlugFromControl } from '@abp/ng.cms-kit';
import { BlogPostAdminService, BlogPostDto } from '@abp/ng.cms-kit/proxy';
import { eCmsKitAdminComponents } from '../../../enums';
import { BlogPostFormService } from '../../../services';

@Component({
selector: 'abp-blog-post-form',
templateUrl: './blog-post-form.component.html',
providers: [
{
provide: EXTENSIONS_IDENTIFIER,
useValue: eCmsKitAdminComponents.BlogPostForm,
},
],
imports: [
ButtonComponent,
ExtensibleFormComponent,
PageComponent,
ToastuiEditorComponent,
LocalizationPipe,
ReactiveFormsModule,
CommonModule,
NgxValidateCoreModule,
],
})
export class BlogPostFormComponent implements OnInit {
private blogPostService = inject(BlogPostAdminService);
private injector = inject(Injector);
private blogPostFormService = inject(BlogPostFormService);
private route = inject(ActivatedRoute);
private destroyRef = inject(DestroyRef);

form: FormGroup;
blogPost: BlogPostDto | null = null;
blogPostId: string | null = null;
isEditMode = false;

ngOnInit() {
const id = this.route.snapshot.params['id'];
if (id) {
this.isEditMode = true;
this.blogPostId = id;
this.loadBlogPost(id);
} else {
this.isEditMode = false;
this.buildForm();
}
}

private loadBlogPost(id: string) {
this.blogPostService.get(id).subscribe(blogPost => {
this.blogPost = blogPost;
this.buildForm();
});
}

private buildForm() {
const data = new FormPropData(this.injector, this.blogPost || {});
const baseForm = generateFormFromProps(data);
this.form = new FormGroup({
...baseForm.controls,
content: new FormControl(this.blogPost?.content || ''),
});
prepareSlugFromControl(this.form, 'title', 'slug', this.destroyRef);
}

private executeSaveOperation(operation: 'save' | 'draft' | 'publish' | 'sendToReview') {
if (this.isEditMode) {
if (!this.blogPost || !this.blogPostId) {
return;
}
this.blogPostFormService.update(this.blogPostId, this.form, this.blogPost).subscribe();
return;
}

switch (operation) {
case 'save':
this.blogPostFormService.createAsDraft(this.form).subscribe();
break;
case 'draft':
this.blogPostFormService.createAsDraft(this.form).subscribe();
break;
case 'publish':
this.blogPostFormService.createAndPublish(this.form).subscribe();
break;
case 'sendToReview':
this.blogPostFormService.createAndSendToReview(this.form).subscribe();
break;
}
}

saveAsDraft() {
this.executeSaveOperation('draft');
}

publish() {
this.executeSaveOperation('publish');
}

sendToReview() {
this.executeSaveOperation('sendToReview');
}
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
<abp-page [title]="'CmsKit::BlogPosts' | abpLocalization" [toolbar]="data.items">
<div class="card mb-4">
<div class="card-body">
<div class="row">
<div class="col-2">
<select class="form-select" [(ngModel)]="statusFilter" (change)="onStatusChange()">
<option [ngValue]="null">{{ 'CmsKit::AllPosts' | abpLocalization }}</option>
<option [ngValue]="BlogPostStatus.Draft">
{{ 'CmsKit::' + 'CmsKit.BlogPost.Status.0' | abpLocalization }}
</option>
<option [ngValue]="BlogPostStatus.Published">
{{ 'CmsKit::' + 'CmsKit.BlogPost.Status.1' | abpLocalization }}
</option>
<option [ngValue]="BlogPostStatus.WaitingForReview">
{{ 'CmsKit::' + 'CmsKit.BlogPost.Status.2' | abpLocalization }}
</option>
</select>
</div>
<div class="col-10">
<div class="input-group">
<input
type="search"
class="form-control"
[placeholder]="'AbpUi::PagerSearch' | abpLocalization"
[(ngModel)]="filter"
(keyup.enter)="onSearch()"
/>
<button class="btn btn-primary" type="button" (click)="onSearch()">
<i class="fa fa-search" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
</div>
</div>

<div class="card">
<abp-extensible-table [data]="data.items" [recordsTotal]="data.totalCount" [list]="list" />
</div>
</abp-page>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
import { Component, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ListService, PagedResultDto, LocalizationPipe } from '@abp/ng.core';
import { ExtensibleTableComponent, EXTENSIONS_IDENTIFIER } from '@abp/ng.components/extensible';
import { PageComponent } from '@abp/ng.components/page';
import {
BlogPostAdminService,
BlogPostGetListInput,
BlogPostListDto,
BlogPostStatus,
} from '@abp/ng.cms-kit/proxy';
import { eCmsKitAdminComponents } from '../../../enums';

@Component({
selector: 'abp-blog-post-list',
templateUrl: './blog-post-list.component.html',
providers: [
ListService,
{
provide: EXTENSIONS_IDENTIFIER,
useValue: eCmsKitAdminComponents.BlogPosts,
},
],
imports: [ExtensibleTableComponent, PageComponent, LocalizationPipe, FormsModule, CommonModule],
})
export class BlogPostListComponent implements OnInit {
data: PagedResultDto<BlogPostListDto> = { items: [], totalCount: 0 };

public readonly list = inject(ListService<BlogPostGetListInput>);
private blogPostService = inject(BlogPostAdminService);

filter = '';
statusFilter: BlogPostStatus | null = null;
BlogPostStatus = BlogPostStatus;

ngOnInit() {
this.hookToQuery();
}

onSearch() {
this.list.filter = this.filter;
this.list.get();
}

onStatusChange() {
this.list.get();
}

private hookToQuery() {
this.list
.hookToQuery(query => {
let filters: Partial<BlogPostGetListInput> = {};
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;
});
}
}
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
export * from './blog-post-list/blog-post-list.component';
export * from './blog-post-form/blog-post-form.component';
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,6 @@ export * from './comments';
export * from './tags';
export * from './pages';
export * from './blogs';
//export * from './blog-posts';
export * from './blog-posts';
// export * from './menus';
// export * from './global-resources';
Loading

[8]ページ先頭

©2009-2025 Movatter.jp