@tager/admin-blog 0.3.21 → 0.3.25

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 (86) hide show
  1. package/dist/index.esm.js +3452 -612
  2. package/dist/index.umd.js +3454 -619
  3. package/package.json +13 -7
  4. package/src/constants/menu.ts +0 -2
  5. package/src/constants/paths.ts +0 -5
  6. package/src/constants/routes.ts +5 -18
  7. package/src/constants/scopes.ts +11 -0
  8. package/src/dev.ts +11 -44
  9. package/src/hooks/index.ts +6 -0
  10. package/src/hooks/useBlogCategoryList.ts +3 -5
  11. package/src/hooks/useBlogPostList.ts +2 -4
  12. package/src/hooks/useModuleConfig.ts +4 -8
  13. package/src/hooks/useStore.ts +8 -0
  14. package/src/hooks/useUserPermission.ts +16 -0
  15. package/src/hooks/useUserProfile.ts +13 -0
  16. package/src/locales/en.ts +17 -5
  17. package/src/locales/ru.ts +17 -4
  18. package/src/router/index.ts +39 -0
  19. package/src/services/requests.ts +33 -43
  20. package/src/store/index.ts +21 -0
  21. package/src/store/user.ts +109 -0
  22. package/src/typings/common.ts +1 -0
  23. package/src/typings/model.ts +62 -38
  24. package/src/utils/common.ts +23 -0
  25. package/src/views/App.vue +10 -4
  26. package/src/views/{BlogCategoryForm/BlogCategoryForm.helpers.ts → Categories/CategoryForm/CategoryForm.helpers.ts} +22 -7
  27. package/src/views/{BlogCategoryForm/BlogCategoryForm.vue → Categories/CategoryForm/CategoryForm.vue} +140 -63
  28. package/src/views/Categories/CategoryForm/index.ts +1 -0
  29. package/src/views/Categories/CategoryList/CategoryList.helpers.ts +91 -0
  30. package/src/views/Categories/CategoryList/CategoryList.vue +269 -0
  31. package/src/views/Categories/CategoryList/hooks/index.ts +1 -0
  32. package/src/views/Categories/CategoryList/hooks/useAdvancedSearch.ts +95 -0
  33. package/src/views/Categories/CategoryList/index.ts +1 -0
  34. package/src/views/Home.vue +2 -9
  35. package/src/views/Posts/PostForm/PostForm.helpers.ts +150 -0
  36. package/src/views/Posts/PostForm/PostForm.vue +550 -0
  37. package/src/views/{BlogPostForm → Posts/PostForm}/components/TabList/TabList.types.ts +0 -0
  38. package/src/views/{BlogPostForm → Posts/PostForm}/components/TabList/TabList.vue +1 -1
  39. package/src/views/{BlogPostForm → Posts/PostForm}/components/TabList/index.ts +0 -0
  40. package/src/views/Posts/PostForm/index.ts +1 -0
  41. package/src/views/{BlogPostList/BlogPostList.helpers.ts → Posts/PostList/PostList.helpers.ts} +10 -18
  42. package/src/views/Posts/PostList/PostList.vue +361 -0
  43. package/src/views/Posts/PostList/hooks/index.ts +1 -0
  44. package/src/views/Posts/PostList/hooks/useAdvancedSearch.ts +250 -0
  45. package/src/views/Posts/PostList/index.ts +1 -0
  46. package/dist/constants/menu.d.ts +0 -5
  47. package/dist/constants/paths.d.ts +0 -16
  48. package/dist/constants/routes.d.ts +0 -6
  49. package/dist/dev.d.ts +0 -3
  50. package/dist/hooks/useBlogCategoryList.d.ts +0 -7
  51. package/dist/hooks/useBlogPostList.d.ts +0 -7
  52. package/dist/hooks/useModuleConfig.d.ts +0 -7
  53. package/dist/locales/en.d.ts +0 -63
  54. package/dist/locales/ru.d.ts +0 -3
  55. package/dist/main.d.ts +0 -4
  56. package/dist/services/requests.d.ts +0 -68
  57. package/dist/typings/model.d.ts +0 -74
  58. package/dist/views/BlogCategoryForm/BlogCategoryForm.helpers.d.ts +0 -16
  59. package/dist/views/BlogCategoryForm/BlogCategoryForm.vue.d.ts +0 -86
  60. package/dist/views/BlogCategoryForm/index.d.ts +0 -1
  61. package/dist/views/BlogCategoryList/BlogCategoryList.helpers.d.ts +0 -6
  62. package/dist/views/BlogCategoryList/BlogCategoryList.vue.d.ts +0 -3
  63. package/dist/views/BlogCategoryList/index.d.ts +0 -1
  64. package/dist/views/BlogPostForm/BlogPostForm.helpers.d.ts +0 -27
  65. package/dist/views/BlogPostForm/BlogPostForm.vue.d.ts +0 -9320
  66. package/dist/views/BlogPostForm/components/TabList/TabList.types.d.ts +0 -5
  67. package/dist/views/BlogPostForm/components/TabList/index.d.ts +0 -2
  68. package/dist/views/BlogPostForm/index.d.ts +0 -1
  69. package/dist/views/BlogPostList/BlogPostList.helpers.d.ts +0 -6
  70. package/dist/views/BlogPostList/BlogPostList.vue.d.ts +0 -45
  71. package/dist/views/BlogPostList/index.d.ts +0 -1
  72. package/dist/views/BlogSettings/BlogSettings.helpers.d.ts +0 -6
  73. package/dist/views/BlogSettings/BlogSettings.vue.d.ts +0 -9132
  74. package/dist/views/BlogSettings/index.d.ts +0 -1
  75. package/src/views/BlogCategoryForm/index.ts +0 -1
  76. package/src/views/BlogCategoryList/BlogCategoryList.helpers.ts +0 -82
  77. package/src/views/BlogCategoryList/BlogCategoryList.vue +0 -196
  78. package/src/views/BlogCategoryList/index.ts +0 -1
  79. package/src/views/BlogPostForm/BlogPostForm.helpers.ts +0 -152
  80. package/src/views/BlogPostForm/BlogPostForm.vue +0 -534
  81. package/src/views/BlogPostForm/index.ts +0 -1
  82. package/src/views/BlogPostList/BlogPostList.vue +0 -174
  83. package/src/views/BlogPostList/index.ts +0 -1
  84. package/src/views/BlogSettings/BlogSettings.helpers.ts +0 -25
  85. package/src/views/BlogSettings/BlogSettings.vue +0 -110
  86. package/src/views/BlogSettings/index.ts +0 -1
@@ -1 +0,0 @@
1
- export { default } from './BlogSettings.vue';
@@ -1 +0,0 @@
1
- export { default } from './BlogCategoryForm.vue';
@@ -1,82 +0,0 @@
1
- import {TFunction} from 'i18next';
2
-
3
- import {notEmpty, Nullable} from '@tager/admin-services';
4
- import {ColumnDefinition} from '@tager/admin-ui';
5
-
6
- import {BlogCategory, BlogModuleConfigType} from '../../typings/model';
7
- import {getBlogCategoryFormUrl} from '../../constants/paths';
8
-
9
- export function convertCategoryList(
10
- categoryList: Array<BlogCategory>,
11
- languages: BlogModuleConfigType['languages']
12
- ): Array<BlogCategory> {
13
- return categoryList.map((category) => {
14
- if (languages.length > 0) {
15
- const foundLanguage = languages.find(
16
- (lang) => category.language === lang.id
17
- );
18
-
19
- return {
20
- ...category,
21
- language: foundLanguage ? foundLanguage.name : category.language,
22
- };
23
- }
24
-
25
- return category;
26
- });
27
- }
28
-
29
- export function getCategoryTableColumnDefs(
30
- moduleConfig: Nullable<BlogModuleConfigType>,
31
- t: TFunction
32
- ): Array<ColumnDefinition<BlogCategory>> {
33
- const isLangSpecific = moduleConfig
34
- ? moduleConfig.languages.length > 0
35
- : false;
36
-
37
- const COLUMN_DEFS: Array<ColumnDefinition<BlogCategory> | null> = [
38
- {
39
- id: 2,
40
- name: t('blog:name'),
41
- field: 'name',
42
- type: 'name',
43
- format: ({row}) => {
44
- return {
45
- adminLink: {
46
- url: getBlogCategoryFormUrl({categoryId: row.id}),
47
- text: row.name,
48
- },
49
- websiteLink: {
50
- url: [
51
- process.env.VUE_APP_WEBSITE_URL || window.location.origin,
52
- row.url,
53
- ].join(''),
54
- text: row.url,
55
- },
56
- paramList: row.isDefault ? [
57
- {name: t('blog:defaultCategory'), 'value': t('blog:yes')}
58
- ] : []
59
- };
60
- },
61
- },
62
- isLangSpecific
63
- ? {id: 4, name: t('blog:language'), field: 'language'}
64
- : null,
65
- {
66
- id: 3,
67
- name: t('blog:posts'),
68
- field: 'linkToPosts',
69
- style: {whiteSpace: 'nowrap', width: '130px'},
70
- },
71
- {
72
- id: 4,
73
- name: t('blog:actions'),
74
- field: 'actions',
75
- style: {whiteSpace: 'nowrap', width: '205px'},
76
- headStyle: {whiteSpace: 'nowrap', width: '205px'},
77
- class: 'actions-cell',
78
- },
79
- ];
80
-
81
- return COLUMN_DEFS.filter(notEmpty);
82
- }
@@ -1,196 +0,0 @@
1
- <template>
2
- <page
3
- :title="$t('blog:blogCategories')"
4
- :header-buttons="[
5
- {
6
- text: $t('blog:newCategory'),
7
- href: getBlogCategoryFormUrl({ categoryId: 'create' }),
8
- },
9
- ]"
10
- >
11
- <template v-slot:content>
12
- <base-table
13
- :column-defs="columnDefs"
14
- :row-data="rowData"
15
- :loading="isRowDataLoading"
16
- :error-message="errorMessage"
17
- data-table="blog-category"
18
- >
19
- <template v-slot:cell(link-to-posts)="{ row }">
20
- <count-button
21
- :href="getLinkToPostsByCategory(row.id)"
22
- variant="outline-secondary"
23
- :count="row.postsCount"
24
- >
25
- {{ $t('blog:posts') }}
26
- </count-button>
27
- </template>
28
-
29
- <template v-slot:cell(actions)="{ row, rowIndex }">
30
- <base-button
31
- variant="icon"
32
- :title="$t('blog:edit')"
33
- :disabled="isDeleting(row.id)"
34
- :href="getBlogCategoryFormUrl({ categoryId: row.id })"
35
- >
36
- <svg-icon name="edit"></svg-icon>
37
- </base-button>
38
-
39
- <base-button
40
- variant="icon"
41
- :title="$t('blog:moveUp')"
42
- :disabled="rowIndex === 0 || isCategoryMoving"
43
- @click="moveCategory(row.id, 'up')"
44
- >
45
- <svg-icon name="north"></svg-icon>
46
- </base-button>
47
-
48
- <base-button
49
- variant="icon"
50
- :title="$t('blog:moveDown')"
51
- :disabled="rowIndex === rowData.length - 1 || isCategoryMoving"
52
- @click="moveCategory(row.id, 'down')"
53
- >
54
- <svg-icon name="south"></svg-icon>
55
- </base-button>
56
-
57
- <base-button
58
- variant="icon"
59
- :title="$t('blog:remove')"
60
- :disabled="isDeleting(row.id) || row.postsCount > 0"
61
- @click="handleCategoryDelete(row.id)"
62
- >
63
- <svg-icon name="delete"></svg-icon>
64
- </base-button>
65
- </template>
66
- </base-table>
67
- </template>
68
- </page>
69
- </template>
70
-
71
- <script lang="ts">
72
- import Vue from 'vue';
73
- import { computed, onMounted, ref } from '@vue/composition-api';
74
-
75
- import { useResource, useResourceDelete } from '@tager/admin-services';
76
- import { OptionType } from '@tager/admin-ui';
77
-
78
- import { BlogCategory } from '../../typings/model';
79
- import {
80
- deleteBlogCategory,
81
- getBlogCategoryList,
82
- moveBlogCategory,
83
- } from '../../services/requests';
84
- import {
85
- getBlogCategoryFormUrl,
86
- getBlogPostListUrl,
87
- } from '../../constants/paths';
88
- import useModuleConfig from '../../hooks/useModuleConfig';
89
-
90
- import {
91
- convertCategoryList,
92
- getCategoryTableColumnDefs,
93
- } from './BlogCategoryList.helpers';
94
-
95
- export default Vue.extend({
96
- name: 'BlogCategoryList',
97
- setup(props, context) {
98
- /** Fetch module config */
99
- const {
100
- data: moduleConfig,
101
- loading: isModuleConfigLoading,
102
- } = useModuleConfig({ context });
103
-
104
- const languageOptionList = computed<Array<OptionType>>(
105
- () =>
106
- moduleConfig.value?.languages.map((lang) => ({
107
- value: lang.id,
108
- label: lang.name,
109
- })) ?? []
110
- );
111
-
112
- const isLangSpecific = computed(() => languageOptionList.value.length > 0);
113
-
114
- /** Fetch category list */
115
-
116
- const [
117
- fetchBlogCategoryList,
118
- { data: categoryList, loading: isCategoryListLoading, error },
119
- ] = useResource<Array<BlogCategory>>({
120
- fetchResource: getBlogCategoryList,
121
- initialValue: [],
122
- context,
123
- resourceName: 'Blog category list',
124
- });
125
-
126
- onMounted(() => {
127
- fetchBlogCategoryList();
128
- });
129
-
130
- const {
131
- handleResourceDelete: handleCategoryDelete,
132
- isDeleting,
133
- } = useResourceDelete({
134
- deleteResource: deleteBlogCategory,
135
- resourceName: 'Post',
136
- onSuccess: fetchBlogCategoryList,
137
- context,
138
- });
139
-
140
- const isCategoryMoving = ref<boolean>(false);
141
-
142
- function moveCategory(categoryId: number, direction: 'up' | 'down') {
143
- isCategoryMoving.value = true;
144
-
145
- moveBlogCategory(categoryId, direction)
146
- .then((response) => {
147
- if (response.success) {
148
- return fetchBlogCategoryList();
149
- }
150
- })
151
- .catch(console.error)
152
- .finally(() => {
153
- isCategoryMoving.value = false;
154
- });
155
- }
156
-
157
- /** Misc */
158
-
159
- const isRowDataLoading = computed<boolean>(
160
- () => isCategoryListLoading.value || isModuleConfigLoading.value
161
- );
162
-
163
- function getLinkToPostsByCategory(categoryId: number): string {
164
- return `${getBlogPostListUrl()}?category=${categoryId}`;
165
- }
166
-
167
- const displayedCategoryList = computed<Array<BlogCategory>>(() =>
168
- convertCategoryList(
169
- categoryList.value,
170
- moduleConfig.value?.languages ?? []
171
- )
172
- );
173
-
174
- const columnDefs = computed(() =>
175
- getCategoryTableColumnDefs(moduleConfig.value, context.root.$t)
176
- );
177
-
178
- return {
179
- columnDefs,
180
- rowData: displayedCategoryList,
181
- isRowDataLoading,
182
- errorMessage: error,
183
- isLangSpecific,
184
- languageOptionList,
185
- handleCategoryDelete,
186
- isDeleting,
187
- getBlogCategoryFormUrl,
188
- getLinkToPostsByCategory,
189
- moveCategory,
190
- isCategoryMoving,
191
- };
192
- },
193
- });
194
- </script>
195
-
196
- <style scoped lang="scss"></style>
@@ -1 +0,0 @@
1
- export { default } from './BlogCategoryList.vue';
@@ -1,152 +0,0 @@
1
- import {createId, Nullable} from '@tager/admin-services';
2
- import {OptionType, SingleFileInputValueType} from '@tager/admin-ui';
3
- import {
4
- FieldConfigUnion,
5
- FieldUnion,
6
- universalFieldUtils,
7
- } from '@tager/admin-dynamic-field';
8
-
9
- import {BlogCategory, PostFull} from '../../typings/model';
10
- import {
11
- PostCreationPayload,
12
- PostUpdatePayload,
13
- } from '../../services/requests';
14
-
15
- export type FormValues = {
16
- title: string;
17
- excerpt: string;
18
- body: string;
19
- date: string;
20
- coverImage: Nullable<SingleFileInputValueType>;
21
- image: Nullable<SingleFileInputValueType>;
22
- imageMobile: Nullable<SingleFileInputValueType>;
23
- pageTitle: string;
24
- pageDescription: string;
25
- openGraphImage: Nullable<SingleFileInputValueType>;
26
- urlAlias: string;
27
- categories: Array<OptionType<number>>;
28
- language: Nullable<OptionType>;
29
- relatedPosts: Array<OptionType<number>>;
30
- tags: string;
31
- additionalFields: Array<FieldUnion>;
32
- };
33
-
34
- export function convertPostToFormValues(
35
- post: Nullable<PostFull>,
36
- languageOptionList: Array<OptionType>,
37
- postOptionList: Array<OptionType<number>>,
38
- additionalFieldList: Array<FieldConfigUnion>
39
- ): FormValues {
40
- if (!post) {
41
- return {
42
- title: '',
43
- excerpt: '',
44
- body: '',
45
- date: '',
46
- coverImage: null,
47
- image: null,
48
- imageMobile: null,
49
- pageTitle: '',
50
- pageDescription: '',
51
- openGraphImage: null,
52
- urlAlias: '',
53
- categories: [],
54
- language: null,
55
- relatedPosts: [],
56
- tags: '',
57
- additionalFields: additionalFieldList.map((fieldConfig) =>
58
- universalFieldUtils.createFormField(fieldConfig, null)
59
- ),
60
- };
61
- }
62
-
63
- const currentLangOption = languageOptionList.find(
64
- (option) => option.value === post.language
65
- );
66
-
67
- const selectedPostOptionList = postOptionList.filter((option) =>
68
- post.relatedPosts.some((relatedPost) => relatedPost.id === option.value)
69
- );
70
-
71
- return {
72
- title: post.title,
73
- excerpt: post.excerpt,
74
- body: post.body,
75
- date: post.date,
76
- coverImage: post.coverImage ? {id: createId(), file: post.coverImage} : null,
77
- image: post.image ? {id: createId(), file: post.image} : null,
78
- imageMobile: post.imageMobile ? {id: createId(), file: post.imageMobile} : null,
79
- pageTitle: post.pageTitle ?? '',
80
- pageDescription: post.pageDescription ?? '',
81
- openGraphImage: post.openGraphImage
82
- ? {id: createId(), file: post.openGraphImage}
83
- : null,
84
- urlAlias: post.urlAlias,
85
- categories: post.categories.map((category) => ({
86
- value: category.id,
87
- label: category.name,
88
- })),
89
- language: currentLangOption ?? null,
90
- relatedPosts: selectedPostOptionList,
91
- tags: post.tags.join(','),
92
- additionalFields: additionalFieldList.map((fieldConfig, index) => {
93
- const postAdditionalField = post.additionalFields.find(item => item.name === fieldConfig.name);
94
- return universalFieldUtils.createFormField(
95
- fieldConfig,
96
- postAdditionalField?.value
97
- );
98
- }),
99
- };
100
- }
101
-
102
- export function convertFormValuesToCreationPayload(
103
- values: FormValues
104
- ): PostCreationPayload {
105
- return {
106
- title: values.title,
107
- excerpt: values.excerpt,
108
- urlAlias: values.urlAlias,
109
- body: values.body,
110
- date: values.date,
111
- coverImage: values.coverImage?.file.id ?? null,
112
- image: values.image?.file.id ?? null,
113
- imageMobile: values.imageMobile?.file.id ?? null,
114
- pageTitle: values.pageTitle,
115
- pageDescription: values.pageDescription,
116
- openGraphImage: values.openGraphImage?.file.id ?? null,
117
- status: 'PUBLISHED',
118
- categories: values.categories.map((option) => option.value),
119
- language: values.language?.value ?? null,
120
- relatedPosts: values.relatedPosts.map(
121
- (relatedPostOption) => relatedPostOption.value
122
- ),
123
- tags: values.tags.split(',').filter((tag) => tag.trim().length > 0),
124
- additionalFields: values.additionalFields.map((field) => ({
125
- name: field.config.name,
126
- value: universalFieldUtils.getOutgoingValue(field),
127
- })),
128
- };
129
- }
130
-
131
- export function convertFormValuesToUpdatePayload(
132
- values: FormValues
133
- ): PostUpdatePayload {
134
- return {
135
- ...convertFormValuesToCreationPayload(values),
136
- urlAlias: values.urlAlias,
137
- };
138
- }
139
-
140
- export function convertCategoryListToOptions(
141
- categoryList: Array<BlogCategory>,
142
- languageId: Nullable<string>
143
- ): Array<OptionType<number>> {
144
- return categoryList
145
- .filter((category) =>
146
- languageId ? category.language === languageId : true
147
- )
148
- .map((category) => ({
149
- value: category.id,
150
- label: category.name,
151
- }));
152
- }