@tager/admin-blog 0.3.23 → 0.3.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/constants/scopes.d.ts +11 -0
  2. package/dist/dev.d.ts +0 -2
  3. package/dist/hooks/index.d.ts +7 -3
  4. package/dist/hooks/{useBlogCategoryList.d.ts → useFetchCategories.d.ts} +2 -2
  5. package/dist/hooks/useFetchCategory.d.ts +8 -0
  6. package/dist/hooks/{useModuleConfig.d.ts → useFetchModuleConfig.d.ts} +2 -2
  7. package/dist/hooks/{useBlogPostList.d.ts → useFetchPosts.d.ts} +2 -2
  8. package/dist/hooks/useStore.d.ts +4 -0
  9. package/dist/hooks/useUserPermission.d.ts +3 -0
  10. package/dist/hooks/useUserProfile.d.ts +3 -0
  11. package/dist/index.esm.js +1245 -432
  12. package/dist/index.umd.js +1253 -438
  13. package/dist/locales/en.d.ts +10 -1
  14. package/dist/router/index.d.ts +4 -0
  15. package/dist/services/requests.d.ts +13 -22
  16. package/dist/store/index.d.ts +6 -0
  17. package/dist/store/user.d.ts +14 -0
  18. package/dist/typings/common.d.ts +1 -0
  19. package/dist/typings/model.d.ts +45 -1
  20. package/dist/utils/common.d.ts +4 -0
  21. package/dist/views/Categories/CategoryForm/CategoryForm.helpers.d.ts +3 -14
  22. package/dist/views/Categories/CategoryForm/CategoryForm.vue.d.ts +45 -22
  23. package/dist/views/Categories/CategoryList/CategoryList.helpers.d.ts +2 -2
  24. package/dist/views/Categories/CategoryList/CategoryList.vue.d.ts +6 -4
  25. package/dist/views/Categories/CategoryList/hooks/useAdvancedSearch.d.ts +1 -1
  26. package/dist/views/Posts/PostForm/PostForm.helpers.d.ts +2 -2
  27. package/dist/views/Posts/PostForm/PostForm.vue.d.ts +2 -0
  28. package/dist/views/Posts/PostList/PostList.helpers.d.ts +2 -2
  29. package/dist/views/Posts/PostList/PostList.vue.d.ts +8 -2
  30. package/dist/views/Posts/PostList/hooks/useAdvancedSearch.d.ts +1 -1
  31. package/package.json +9 -5
  32. package/src/constants/scopes.ts +11 -0
  33. package/src/dev.ts +11 -42
  34. package/src/hooks/index.ts +7 -3
  35. package/src/hooks/useFetchCategories.ts +25 -0
  36. package/src/hooks/useFetchCategory.ts +41 -0
  37. package/src/hooks/{useModuleConfig.ts → useFetchModuleConfig.ts} +7 -5
  38. package/src/hooks/useFetchPosts.ts +23 -0
  39. package/src/hooks/useStore.ts +8 -0
  40. package/src/hooks/useUserPermission.ts +16 -0
  41. package/src/hooks/useUserProfile.ts +13 -0
  42. package/src/locales/en.ts +13 -1
  43. package/src/locales/ru.ts +14 -2
  44. package/src/router/index.ts +39 -0
  45. package/src/services/requests.ts +30 -26
  46. package/src/store/index.ts +21 -0
  47. package/src/store/user.ts +109 -0
  48. package/src/typings/common.ts +1 -0
  49. package/src/typings/model.ts +54 -1
  50. package/src/utils/common.ts +23 -0
  51. package/src/views/App.vue +10 -2
  52. package/src/views/Categories/CategoryForm/CategoryForm.helpers.ts +26 -35
  53. package/src/views/Categories/CategoryForm/CategoryForm.vue +180 -113
  54. package/src/views/Categories/CategoryList/CategoryList.helpers.ts +41 -36
  55. package/src/views/Categories/CategoryList/CategoryList.vue +42 -25
  56. package/src/views/Categories/CategoryList/hooks/useAdvancedSearch.ts +1 -1
  57. package/src/views/Home.vue +1 -1
  58. package/src/views/Posts/PostForm/PostForm.helpers.ts +7 -6
  59. package/src/views/Posts/PostForm/PostForm.vue +57 -22
  60. package/src/views/Posts/PostList/PostList.helpers.ts +13 -15
  61. package/src/views/Posts/PostList/PostList.vue +96 -34
  62. package/src/views/Posts/PostList/hooks/useAdvancedSearch.ts +6 -5
  63. package/src/hooks/useBlogCategoryList.ts +0 -23
  64. package/src/hooks/useBlogPostList.ts +0 -23
@@ -0,0 +1,41 @@
1
+ import { onMounted, Ref, SetupContext, watch } from '@vue/composition-api';
2
+
3
+ import { Nullable, ResourceRef, useResource } from '@tager/admin-services';
4
+
5
+ import { Category } from '@/typings/model';
6
+ import { getCategory } from '@/services/requests';
7
+
8
+ export function useFetchCategory({
9
+ context,
10
+ categoryId,
11
+ isCreation,
12
+ }: {
13
+ context: SetupContext;
14
+ categoryId: Ref<string>;
15
+ isCreation: Ref<boolean>;
16
+ }): ResourceRef<Nullable<Category>> {
17
+ const [fetchCategory, resource] = useResource<Nullable<Category>>({
18
+ fetchResource: () => getCategory(categoryId.value),
19
+ initialValue: null,
20
+ context,
21
+ resourceName: 'Blog category',
22
+ });
23
+
24
+ onMounted(() => {
25
+ if (isCreation.value) {
26
+ return;
27
+ }
28
+
29
+ fetchCategory();
30
+ });
31
+
32
+ watch(categoryId, () => {
33
+ if (isCreation.value) {
34
+ return;
35
+ }
36
+
37
+ fetchCategory();
38
+ });
39
+
40
+ return resource;
41
+ }
@@ -2,16 +2,18 @@ import { onMounted, SetupContext } from '@vue/composition-api';
2
2
 
3
3
  import { Nullable, ResourceRef, useResource } from '@tager/admin-services';
4
4
 
5
- import { ModuleConfig } from '../typings/model';
6
- import { getBlogModuleConfig } from '../services/requests';
5
+ import { ModuleConfig } from '@/typings/model';
6
+ import { getModuleConfig } from '@/services/requests';
7
7
 
8
- export function useModuleConfig(params: {
8
+ export function useFetchModuleConfig({
9
+ context,
10
+ }: {
9
11
  context: SetupContext;
10
12
  }): ResourceRef<Nullable<ModuleConfig>> {
11
13
  const [fetchModuleConfig, resource] = useResource<Nullable<ModuleConfig>>({
12
- fetchResource: getBlogModuleConfig,
14
+ fetchResource: getModuleConfig,
13
15
  initialValue: null,
14
- context: params.context,
16
+ context: context,
15
17
  resourceName: 'Module configuration',
16
18
  });
17
19
 
@@ -0,0 +1,23 @@
1
+ import { onMounted, SetupContext } from '@vue/composition-api';
2
+
3
+ import { ResourceRef, useResource } from '@tager/admin-services';
4
+
5
+ import { PostShort } from '@/typings/model';
6
+ import { getPosts } from '@/services/requests';
7
+
8
+ export function useFetchPosts(params: {
9
+ context: SetupContext;
10
+ }): ResourceRef<PostShort[]> {
11
+ const [fetchPosts, resource] = useResource<PostShort[]>({
12
+ fetchResource: () => getPosts({ pageNumber: 1, pageSize: 99999 }),
13
+ initialValue: [],
14
+ context: params.context,
15
+ resourceName: 'Blog posts',
16
+ });
17
+
18
+ onMounted(() => {
19
+ fetchPosts();
20
+ });
21
+
22
+ return resource;
23
+ }
@@ -0,0 +1,8 @@
1
+ import { Store } from 'vuex';
2
+ import { SetupContext } from '@vue/composition-api';
3
+
4
+ import { RootState } from '@/store';
5
+
6
+ export function useStore(context: SetupContext): Store<RootState> {
7
+ return context.root.$store;
8
+ }
@@ -0,0 +1,16 @@
1
+ import { computed, ComputedRef, SetupContext } from '@vue/composition-api';
2
+
3
+ import { ScopeType } from '@/typings/model';
4
+ import { useStore } from '@/hooks/useStore';
5
+ import { userNamespace } from '@/utils/common';
6
+
7
+ export function useUserPermission(
8
+ context: SetupContext,
9
+ scope: ScopeType
10
+ ): ComputedRef<boolean> {
11
+ const store = useStore(context);
12
+
13
+ return computed<boolean>(() => {
14
+ return store.getters[userNamespace('userHasPermission')](scope);
15
+ });
16
+ }
@@ -0,0 +1,13 @@
1
+ import { computed, ComputedRef, SetupContext } from '@vue/composition-api';
2
+
3
+ import { UserModel } from '@/typings/model';
4
+ import { useStore } from '@/hooks/useStore';
5
+ import { userNamespace } from '@/utils/common';
6
+
7
+ export function useUserProfile(context: SetupContext): ComputedRef<UserModel> {
8
+ const store = useStore(context);
9
+
10
+ return computed<UserModel>(() => {
11
+ return store.getters[userNamespace('userProfile')];
12
+ });
13
+ }
package/src/locales/en.ts CHANGED
@@ -31,7 +31,7 @@ const EN = {
31
31
  actions: 'Actions',
32
32
  updatePost: 'Update post',
33
33
  title: 'Title',
34
- URLAlias: 'URL alias',
34
+ link: 'Link',
35
35
  excerpt: 'Excerpt',
36
36
  body: 'Body',
37
37
  defaultCategory: 'Default Category',
@@ -62,6 +62,18 @@ const EN = {
62
62
  blogCategoryWasSuccessfullyUpdated: 'Blog category was successfully updated',
63
63
  blogCategoryCreationWasFailed: 'Blog category creation was failed',
64
64
  blogCategoryUpdateWasFailed: 'Blog category update was failed',
65
+
66
+ clone: 'Clone',
67
+ cloneConfirm: 'Are you sure you want to clone the page?',
68
+ cloneSuccess: 'Page have copied successfully',
69
+ cloneFailure: 'Page copy failure',
70
+
71
+ tabs: {
72
+ common: 'Common',
73
+ seo: 'SEO',
74
+ },
75
+
76
+ parentCategory: 'Parent category',
65
77
  };
66
78
 
67
79
  export default EN;
package/src/locales/ru.ts CHANGED
@@ -19,7 +19,7 @@ const RU: typeof EN = {
19
19
  edit: 'Редактировать',
20
20
  remove: 'Удалить',
21
21
  postsByCategory: 'Посты по категориям',
22
- name: 'Имя',
22
+ name: 'Название',
23
23
  image: 'Изображение',
24
24
  language: 'Язык',
25
25
  languages: 'Языки',
@@ -33,7 +33,7 @@ const RU: typeof EN = {
33
33
  actions: 'Действия',
34
34
  updatePost: 'Обновить пост',
35
35
  title: 'Заголовок',
36
- URLAlias: 'URL',
36
+ link: 'Ссылка',
37
37
  excerpt: 'Краткое описание',
38
38
  defaultCategory: 'Категория по-умолчанию',
39
39
  body: 'Содержание',
@@ -64,6 +64,18 @@ const RU: typeof EN = {
64
64
  blogCategoryWasSuccessfullyUpdated: 'Категория блога успешно обновлена',
65
65
  blogCategoryCreationWasFailed: 'Не удалось создать категорию блога',
66
66
  blogCategoryUpdateWasFailed: 'Не удалось обновить категорию блога',
67
+
68
+ clone: 'Клонировать',
69
+ cloneConfirm: 'Вы уверены, что хотите создать копию страницы?',
70
+ cloneSuccess: 'Копия страницы успешно создана',
71
+ cloneFailure: 'Ошибка копирования страницы',
72
+
73
+ tabs: {
74
+ common: 'Общие',
75
+ seo: 'SEO',
76
+ },
77
+
78
+ parentCategory: 'Родительская категория',
67
79
  };
68
80
 
69
81
  export default RU;
@@ -0,0 +1,39 @@
1
+ import {
2
+ createRouter,
3
+ CustomRoute,
4
+ CustomRouteConfig,
5
+ } from '@tager/admin-layout';
6
+
7
+ import {
8
+ BLOG_CATEGORY_FORM_ROUTE,
9
+ BLOG_CATEGORY_LIST_ROUTE,
10
+ BLOG_POST_FORM_ROUTE,
11
+ BLOG_POST_LIST_ROUTE,
12
+ } from '@/constants/routes';
13
+ import Home from '@/views/Home.vue';
14
+
15
+ export const HOME_ROUTE: CustomRouteConfig = {
16
+ path: '/',
17
+ component: Home,
18
+ name: 'Home',
19
+ meta: {
20
+ getBreadcrumbs: (route: CustomRoute) => [
21
+ { url: '/', text: route.name ?? '' },
22
+ ],
23
+ },
24
+ };
25
+
26
+ const router = createRouter(
27
+ {
28
+ routes: [
29
+ HOME_ROUTE,
30
+ BLOG_POST_LIST_ROUTE,
31
+ BLOG_POST_FORM_ROUTE,
32
+ BLOG_CATEGORY_LIST_ROUTE,
33
+ BLOG_CATEGORY_FORM_ROUTE,
34
+ ],
35
+ },
36
+ { useTitleSync: false }
37
+ );
38
+
39
+ export default router;
@@ -1,11 +1,22 @@
1
1
  import { request, Nullable, ResponseBody } from '@tager/admin-services';
2
2
  import { FieldShortType, OutgoingValueUnion } from '@tager/admin-dynamic-field';
3
3
 
4
- import { Category, ModuleConfig, PostShort, PostFull } from '../typings/model';
4
+ import {
5
+ Category,
6
+ ModuleConfig,
7
+ PostShort,
8
+ PostFull,
9
+ UserModel,
10
+ CategoryPayload,
11
+ } from '@/typings/model';
12
+
13
+ export function getUserProfile(): Promise<ResponseBody<UserModel>> {
14
+ return request.get({ path: '/admin/self' });
15
+ }
5
16
 
6
17
  /** Blog Posts */
7
18
 
8
- export function getBlogPostList(params?: {
19
+ export function getPosts(params?: {
9
20
  query?: string;
10
21
  pageNumber?: number;
11
22
  pageSize?: number;
@@ -13,16 +24,22 @@ export function getBlogPostList(params?: {
13
24
  return request.get({ path: '/admin/blog/posts', params });
14
25
  }
15
26
 
16
- export function getBlogPostCount(): Promise<ResponseBody<{ count: number }>> {
27
+ export function getPostsCount(): Promise<ResponseBody<{ count: number }>> {
17
28
  return request.get({ path: '/admin/blog/posts/count' });
18
29
  }
19
30
 
20
- export function getBlogPost(
31
+ export function getPost(
21
32
  postId: number | string
22
33
  ): Promise<ResponseBody<PostFull>> {
23
34
  return request.get({ path: `/admin/blog/posts/${postId}` });
24
35
  }
25
36
 
37
+ export function clonePost(
38
+ postId: number | string
39
+ ): Promise<ResponseBody<PostFull>> {
40
+ return request.post({ path: `/admin/blog/posts/${postId}/clone` });
41
+ }
42
+
26
43
  export interface PostCreationPayload {
27
44
  title: string;
28
45
  urlAlias: string;
@@ -68,7 +85,7 @@ export function deleteBlogPost(
68
85
 
69
86
  /** Blog Categories */
70
87
 
71
- export function getBlogCategoryList(params?: {
88
+ export function getCategories(params?: {
72
89
  query?: string;
73
90
  pageNumber?: number;
74
91
  pageSize?: number;
@@ -76,34 +93,21 @@ export function getBlogCategoryList(params?: {
76
93
  return request.get({ path: '/admin/blog/categories', params });
77
94
  }
78
95
 
79
- export function getBlogCategory(
96
+ export function getCategory(
80
97
  categoryId: number | string
81
98
  ): Promise<ResponseBody<Category>> {
82
99
  return request.get({ path: `/admin/blog/categories/${categoryId}` });
83
100
  }
84
101
 
85
- export interface BlogCategoryCreationPayload {
86
- name: string;
87
- isDefault: boolean;
88
- pageTitle: Nullable<string>;
89
- language: Nullable<string>;
90
- pageDescription: Nullable<string>;
91
- openGraphImage: Nullable<string>;
92
- }
93
-
94
- export function createBlogCategory(
95
- payload: BlogCategoryCreationPayload
102
+ export function createCategory(
103
+ payload: CategoryPayload
96
104
  ): Promise<ResponseBody<Category>> {
97
105
  return request.post({ path: '/admin/blog/categories', body: payload });
98
106
  }
99
107
 
100
- export type BlogCategoryUpdatePayload = BlogCategoryCreationPayload & {
101
- urlAlias: string;
102
- };
103
-
104
- export function updateBlogCategory(
108
+ export function updateCategory(
105
109
  categoryId: number | string,
106
- payload: BlogCategoryUpdatePayload
110
+ payload: CategoryPayload
107
111
  ): Promise<ResponseBody<Category>> {
108
112
  return request.put({
109
113
  path: `/admin/blog/categories/${categoryId}`,
@@ -111,7 +115,7 @@ export function updateBlogCategory(
111
115
  });
112
116
  }
113
117
 
114
- export function deleteBlogCategory(
118
+ export function deleteCategory(
115
119
  categoryId: number | string
116
120
  ): Promise<{ success: boolean }> {
117
121
  return request.delete({
@@ -119,7 +123,7 @@ export function deleteBlogCategory(
119
123
  });
120
124
  }
121
125
 
122
- export function moveBlogCategory(
126
+ export function moveCategory(
123
127
  categoryId: number | string,
124
128
  direction: 'up' | 'down'
125
129
  ): Promise<{ success: boolean }> {
@@ -128,7 +132,7 @@ export function moveBlogCategory(
128
132
  });
129
133
  }
130
134
 
131
- export function getBlogModuleConfig(): Promise<ResponseBody<ModuleConfig>> {
135
+ export function getModuleConfig(): Promise<ResponseBody<ModuleConfig>> {
132
136
  return request.get({
133
137
  path: `/admin/blog/module-info`,
134
138
  });
@@ -0,0 +1,21 @@
1
+ import Vue from 'vue';
2
+ import Vuex from 'vuex';
3
+
4
+ import userModule, {
5
+ USER_MODULE_NAMESPACE,
6
+ UserModuleStateModel,
7
+ } from '@/store/user';
8
+
9
+ Vue.use(Vuex);
10
+
11
+ export interface RootState {
12
+ user: UserModuleStateModel;
13
+ }
14
+
15
+ const store = new Vuex.Store({
16
+ modules: {
17
+ [USER_MODULE_NAMESPACE]: userModule,
18
+ },
19
+ });
20
+
21
+ export default store;
@@ -0,0 +1,109 @@
1
+ import { GetterTree, Module } from 'vuex';
2
+
3
+ import { FETCH_STATUSES, FetchStatus } from '@tager/admin-services';
4
+
5
+ import { ScopeType, UserModel } from '@/typings/model';
6
+ import { getUserProfile } from '@/services/requests';
7
+ import { RootState } from '@/store';
8
+ import { Scope } from '@/constants/scopes';
9
+
10
+ export interface UserModuleStateModel {
11
+ profile: UserModel | null;
12
+ status: FetchStatus;
13
+ }
14
+
15
+ export const USER_MODULE_NAMESPACE = 'user';
16
+
17
+ const USER_MUTATION_TYPES = {
18
+ PROFILE_REQUEST_STARTED: 'profileRequestStarted',
19
+ PROFILE_REQUEST_FULFILLED: 'profileRequestFulfilled',
20
+ PROFILE_REQUEST_REJECTED: 'profileRequestRejected',
21
+ };
22
+
23
+ export const USER_ACTION_TYPES = {
24
+ FETCH_USER_PROFILE: 'fetchUserProfile',
25
+ } as const;
26
+
27
+ type ReturnValueMapType<
28
+ T extends { [key: string]: (...args: any[]) => any }
29
+ > = { [key in keyof T]: ReturnType<T[key]> };
30
+
31
+ interface UserGettersType extends GetterTree<UserModuleStateModel, RootState> {
32
+ userScopes: (state: UserModuleStateModel) => Array<ScopeType>;
33
+ userHasPermission: (
34
+ state: UserModuleStateModel,
35
+ getters: ReturnValueMapType<UserGettersType>
36
+ ) => (scope: ScopeType) => boolean;
37
+ }
38
+
39
+ const userGetters: UserGettersType = {
40
+ userProfile(state) {
41
+ return state.profile;
42
+ },
43
+ userScopes(state) {
44
+ const roles = state.profile ? state.profile.roles : [];
45
+ const scopes: Array<ScopeType> = [];
46
+
47
+ roles.forEach((role) => {
48
+ scopes.push(...role.scopes);
49
+ });
50
+
51
+ return scopes;
52
+ },
53
+ userHasPermission: (state, getters) => (scope: ScopeType) => {
54
+ const scopes = getters.userScopes;
55
+
56
+ if (scopes.includes(Scope.All)) return true;
57
+
58
+ return scopes.includes(scope);
59
+ },
60
+ };
61
+
62
+ const userModule: Module<UserModuleStateModel, RootState> = {
63
+ namespaced: true,
64
+ state: {
65
+ profile: null,
66
+ status: FETCH_STATUSES.IDLE,
67
+ },
68
+ mutations: {
69
+ [USER_MUTATION_TYPES.PROFILE_REQUEST_STARTED](state) {
70
+ if (state.status === FETCH_STATUSES.IDLE) {
71
+ state.status = FETCH_STATUSES.LOADING;
72
+ }
73
+ },
74
+ [USER_MUTATION_TYPES.PROFILE_REQUEST_FULFILLED](state, user: UserModel) {
75
+ if (state.status === FETCH_STATUSES.LOADING) {
76
+ state.status = FETCH_STATUSES.SUCCESS;
77
+ state.profile = user;
78
+ }
79
+ },
80
+ [USER_MUTATION_TYPES.PROFILE_REQUEST_REJECTED](state) {
81
+ if (state.status === FETCH_STATUSES.LOADING) {
82
+ state.status = FETCH_STATUSES.FAILURE;
83
+ state.profile = null;
84
+ }
85
+ },
86
+ },
87
+ actions: {
88
+ [USER_ACTION_TYPES.FETCH_USER_PROFILE](store) {
89
+ if (store.state.status !== FETCH_STATUSES.IDLE) return;
90
+
91
+ store.commit(USER_MUTATION_TYPES.PROFILE_REQUEST_STARTED);
92
+
93
+ getUserProfile()
94
+ .then((response) => {
95
+ store.commit(
96
+ USER_MUTATION_TYPES.PROFILE_REQUEST_FULFILLED,
97
+ response.data
98
+ );
99
+ })
100
+ .catch((error) => {
101
+ console.error(error);
102
+ store.commit(USER_MUTATION_TYPES.PROFILE_REQUEST_REJECTED);
103
+ });
104
+ },
105
+ },
106
+ getters: userGetters,
107
+ };
108
+
109
+ export default userModule;
@@ -0,0 +1 @@
1
+ export type Values<T> = T[keyof T];
@@ -4,11 +4,36 @@ import {
4
4
  FieldShortType,
5
5
  IncomingValueUnion,
6
6
  } from '@tager/admin-dynamic-field';
7
- import { ShortCodeItemType } from '@tager/admin-ui';
7
+ import {
8
+ OptionType,
9
+ ShortCodeItemType,
10
+ SingleFileInputValueType,
11
+ } from '@tager/admin-ui';
12
+
13
+ import { Values } from '@/typings/common';
14
+ import { Scope } from '@/constants/scopes';
15
+
16
+ export type ScopeType = Values<typeof Scope>;
17
+
18
+ export interface RoleModel {
19
+ readonly id: number;
20
+ readonly name: string;
21
+ readonly scopes: Array<ScopeType>;
22
+ }
23
+
24
+ export interface UserModel {
25
+ readonly id: number;
26
+ readonly name: string;
27
+ readonly email: string;
28
+ readonly roles: Array<RoleModel>;
29
+ }
8
30
 
9
31
  export interface SeoInfo {
10
32
  readonly pageTitle: Nullable<string>;
11
33
  readonly pageDescription: Nullable<string>;
34
+ readonly pageKeywords: Nullable<string>;
35
+ readonly openGraphTitle: Nullable<string>;
36
+ readonly openGraphDescription: Nullable<string>;
12
37
  readonly openGraphImage: Nullable<FileType>;
13
38
  }
14
39
 
@@ -21,6 +46,8 @@ export interface Category extends SeoInfo {
21
46
  readonly urlTemplate: string;
22
47
  readonly urlAlias: string;
23
48
  readonly postsCount: string;
49
+ readonly parent: Nullable<{ id: number; name: string }>;
50
+ readonly depth: number;
24
51
  }
25
52
 
26
53
  export interface PostShort {
@@ -83,3 +110,29 @@ export interface ModuleConfig {
83
110
  readonly shortcodes: ShortCodeItemType[];
84
111
  readonly fileScenarios: FileScenarios;
85
112
  }
113
+
114
+ export interface CategoryFormValues {
115
+ language: Nullable<OptionType>;
116
+ name: string;
117
+ parent: Nullable<OptionType<number>>;
118
+ urlAlias: string;
119
+
120
+ pageTitle: Nullable<string>;
121
+ pageDescription: Nullable<string>;
122
+ pageKeywords: Nullable<string>;
123
+ openGraphTitle: Nullable<string>;
124
+ openGraphDescription: Nullable<string>;
125
+ openGraphImage: Nullable<SingleFileInputValueType>;
126
+ }
127
+
128
+ export interface CategoryPayload {
129
+ language: Nullable<string>;
130
+ name: string;
131
+ parent: Nullable<number>;
132
+ urlAlias: Nullable<string>;
133
+ isDefault: boolean;
134
+
135
+ pageTitle: Nullable<string>;
136
+ pageDescription: Nullable<string>;
137
+ openGraphImage: Nullable<string>;
138
+ }
@@ -0,0 +1,23 @@
1
+ import { USER_MODULE_NAMESPACE } from '@/store/user';
2
+
3
+ export function namespace(namespace: string, name: string): string {
4
+ return `${namespace}/${name}`;
5
+ }
6
+
7
+ export function userNamespace(name: string): string {
8
+ return namespace(USER_MODULE_NAMESPACE, name);
9
+ }
10
+
11
+ export function generateNumberArray(length: number): Array<number> {
12
+ return Array.from({ length }, (_, index) => index);
13
+ }
14
+
15
+ export function getNameWithDepth(name: string, depth: number): string {
16
+ return (
17
+ generateNumberArray(depth)
18
+ .map(() => '—')
19
+ .join(' ') +
20
+ ' ' +
21
+ name
22
+ );
23
+ }
package/src/views/App.vue CHANGED
@@ -5,15 +5,23 @@
5
5
  </template>
6
6
 
7
7
  <script lang="ts">
8
- import { defineComponent, SetupContext } from '@vue/composition-api';
8
+ import { defineComponent, onMounted, SetupContext } from '@vue/composition-api';
9
9
 
10
- import { getBlogMenuItem } from '../constants/menu';
10
+ import { getBlogMenuItem } from '@/constants/menu';
11
+ import { useStore } from '@/hooks';
12
+ import { USER_ACTION_TYPES } from '@/store/user';
13
+ import { userNamespace } from '@/utils/common';
11
14
 
12
15
  export default defineComponent({
13
16
  name: 'App',
14
17
  setup(props, context: SetupContext) {
18
+ const store = useStore(context);
15
19
  const blogMenuItem = getBlogMenuItem({ t: context.root.$t });
16
20
 
21
+ onMounted(() => {
22
+ store.dispatch(userNamespace(USER_ACTION_TYPES.FETCH_USER_PROFILE));
23
+ });
24
+
17
25
  return {
18
26
  sidebarMenuList: [blogMenuItem],
19
27
  };