@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.
- package/dist/constants/scopes.d.ts +11 -0
- package/dist/dev.d.ts +0 -2
- package/dist/hooks/index.d.ts +7 -3
- package/dist/hooks/{useBlogCategoryList.d.ts → useFetchCategories.d.ts} +2 -2
- package/dist/hooks/useFetchCategory.d.ts +8 -0
- package/dist/hooks/{useModuleConfig.d.ts → useFetchModuleConfig.d.ts} +2 -2
- package/dist/hooks/{useBlogPostList.d.ts → useFetchPosts.d.ts} +2 -2
- package/dist/hooks/useStore.d.ts +4 -0
- package/dist/hooks/useUserPermission.d.ts +3 -0
- package/dist/hooks/useUserProfile.d.ts +3 -0
- package/dist/index.esm.js +1245 -432
- package/dist/index.umd.js +1253 -438
- package/dist/locales/en.d.ts +10 -1
- package/dist/router/index.d.ts +4 -0
- package/dist/services/requests.d.ts +13 -22
- package/dist/store/index.d.ts +6 -0
- package/dist/store/user.d.ts +14 -0
- package/dist/typings/common.d.ts +1 -0
- package/dist/typings/model.d.ts +45 -1
- package/dist/utils/common.d.ts +4 -0
- package/dist/views/Categories/CategoryForm/CategoryForm.helpers.d.ts +3 -14
- package/dist/views/Categories/CategoryForm/CategoryForm.vue.d.ts +45 -22
- package/dist/views/Categories/CategoryList/CategoryList.helpers.d.ts +2 -2
- package/dist/views/Categories/CategoryList/CategoryList.vue.d.ts +6 -4
- package/dist/views/Categories/CategoryList/hooks/useAdvancedSearch.d.ts +1 -1
- package/dist/views/Posts/PostForm/PostForm.helpers.d.ts +2 -2
- package/dist/views/Posts/PostForm/PostForm.vue.d.ts +2 -0
- package/dist/views/Posts/PostList/PostList.helpers.d.ts +2 -2
- package/dist/views/Posts/PostList/PostList.vue.d.ts +8 -2
- package/dist/views/Posts/PostList/hooks/useAdvancedSearch.d.ts +1 -1
- package/package.json +9 -5
- package/src/constants/scopes.ts +11 -0
- package/src/dev.ts +11 -42
- package/src/hooks/index.ts +7 -3
- package/src/hooks/useFetchCategories.ts +25 -0
- package/src/hooks/useFetchCategory.ts +41 -0
- package/src/hooks/{useModuleConfig.ts → useFetchModuleConfig.ts} +7 -5
- package/src/hooks/useFetchPosts.ts +23 -0
- package/src/hooks/useStore.ts +8 -0
- package/src/hooks/useUserPermission.ts +16 -0
- package/src/hooks/useUserProfile.ts +13 -0
- package/src/locales/en.ts +13 -1
- package/src/locales/ru.ts +14 -2
- package/src/router/index.ts +39 -0
- package/src/services/requests.ts +30 -26
- package/src/store/index.ts +21 -0
- package/src/store/user.ts +109 -0
- package/src/typings/common.ts +1 -0
- package/src/typings/model.ts +54 -1
- package/src/utils/common.ts +23 -0
- package/src/views/App.vue +10 -2
- package/src/views/Categories/CategoryForm/CategoryForm.helpers.ts +26 -35
- package/src/views/Categories/CategoryForm/CategoryForm.vue +180 -113
- package/src/views/Categories/CategoryList/CategoryList.helpers.ts +41 -36
- package/src/views/Categories/CategoryList/CategoryList.vue +42 -25
- package/src/views/Categories/CategoryList/hooks/useAdvancedSearch.ts +1 -1
- package/src/views/Home.vue +1 -1
- package/src/views/Posts/PostForm/PostForm.helpers.ts +7 -6
- package/src/views/Posts/PostForm/PostForm.vue +57 -22
- package/src/views/Posts/PostList/PostList.helpers.ts +13 -15
- package/src/views/Posts/PostList/PostList.vue +96 -34
- package/src/views/Posts/PostList/hooks/useAdvancedSearch.ts +6 -5
- package/src/hooks/useBlogCategoryList.ts +0 -23
- package/src/hooks/useBlogPostList.ts +0 -23
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<page
|
|
3
3
|
:title="$t('blog:blogCategories')"
|
|
4
|
-
:header-buttons="
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
:header-buttons="
|
|
5
|
+
[
|
|
6
|
+
canViewAdministrators
|
|
7
|
+
? {
|
|
8
|
+
text: $t('blog:newCategory'),
|
|
9
|
+
href: getBlogCategoryFormUrl({ categoryId: 'create' }),
|
|
10
|
+
}
|
|
11
|
+
: null,
|
|
12
|
+
].filter(Boolean)
|
|
13
|
+
"
|
|
10
14
|
>
|
|
11
15
|
<template v-slot:content>
|
|
12
16
|
<data-table
|
|
@@ -63,7 +67,7 @@
|
|
|
63
67
|
variant="icon"
|
|
64
68
|
:title="$t('blog:moveUp')"
|
|
65
69
|
:disabled="rowIndex === 0 || isCategoryMoving"
|
|
66
|
-
@click="
|
|
70
|
+
@click="startMoveCategory(row.id, 'up')"
|
|
67
71
|
>
|
|
68
72
|
<svg-icon name="north" />
|
|
69
73
|
</base-button>
|
|
@@ -72,7 +76,7 @@
|
|
|
72
76
|
variant="icon"
|
|
73
77
|
:title="$t('blog:moveDown')"
|
|
74
78
|
:disabled="rowIndex === rowData.length - 1 || isCategoryMoving"
|
|
75
|
-
@click="
|
|
79
|
+
@click="startMoveCategory(row.id, 'down')"
|
|
76
80
|
>
|
|
77
81
|
<svg-icon name="south" />
|
|
78
82
|
</base-button>
|
|
@@ -98,14 +102,15 @@ import isEqual from 'lodash.isequal';
|
|
|
98
102
|
import { useResourceDelete } from '@tager/admin-services';
|
|
99
103
|
import { useDataTable } from '@tager/admin-ui';
|
|
100
104
|
|
|
101
|
-
import {
|
|
105
|
+
import { Scope } from '@/constants/scopes';
|
|
106
|
+
import { Category, Language } from '@/typings/model';
|
|
102
107
|
import {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
} from '
|
|
107
|
-
import { getBlogCategoryFormUrl } from '
|
|
108
|
-
import {
|
|
108
|
+
deleteCategory,
|
|
109
|
+
getCategories,
|
|
110
|
+
moveCategory,
|
|
111
|
+
} from '@/services/requests';
|
|
112
|
+
import { getBlogCategoryFormUrl } from '@/constants/paths';
|
|
113
|
+
import { useFetchModuleConfig, useUserPermission } from '@/hooks';
|
|
109
114
|
|
|
110
115
|
import {
|
|
111
116
|
convertCategoryList,
|
|
@@ -117,12 +122,17 @@ import { useAdvancedSearch } from './hooks';
|
|
|
117
122
|
export default defineComponent({
|
|
118
123
|
name: 'BlogCategoryList',
|
|
119
124
|
setup(props, context) {
|
|
120
|
-
|
|
125
|
+
const canViewAdministrators = useUserPermission(
|
|
126
|
+
context,
|
|
127
|
+
Scope.AdministratorsView
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
/** Fetch module config **/
|
|
121
131
|
|
|
122
132
|
const {
|
|
123
133
|
data: moduleConfig,
|
|
124
134
|
loading: isModuleConfigLoading,
|
|
125
|
-
} =
|
|
135
|
+
} = useFetchModuleConfig({ context });
|
|
126
136
|
|
|
127
137
|
const languageList = computed<Language[]>(
|
|
128
138
|
() => moduleConfig.value?.languages ?? []
|
|
@@ -156,7 +166,7 @@ export default defineComponent({
|
|
|
156
166
|
pageSize,
|
|
157
167
|
} = useDataTable<Category>({
|
|
158
168
|
fetchEntityList: (params) =>
|
|
159
|
-
|
|
169
|
+
getCategories({
|
|
160
170
|
query: params.searchQuery,
|
|
161
171
|
pageNumber: params.pageNumber,
|
|
162
172
|
pageSize: params.pageSize,
|
|
@@ -164,7 +174,7 @@ export default defineComponent({
|
|
|
164
174
|
}),
|
|
165
175
|
initialValue: [],
|
|
166
176
|
context,
|
|
167
|
-
resourceName: 'Blog
|
|
177
|
+
resourceName: 'Blog categories',
|
|
168
178
|
pageSize: 100,
|
|
169
179
|
});
|
|
170
180
|
|
|
@@ -185,10 +195,10 @@ export default defineComponent({
|
|
|
185
195
|
});
|
|
186
196
|
|
|
187
197
|
const {
|
|
188
|
-
handleResourceDelete: handleCategoryDelete,
|
|
189
198
|
isDeleting,
|
|
199
|
+
handleResourceDelete: handleCategoryDelete,
|
|
190
200
|
} = useResourceDelete({
|
|
191
|
-
deleteResource:
|
|
201
|
+
deleteResource: deleteCategory,
|
|
192
202
|
resourceName: 'Post',
|
|
193
203
|
onSuccess: fetchCategoryList,
|
|
194
204
|
context,
|
|
@@ -196,10 +206,10 @@ export default defineComponent({
|
|
|
196
206
|
|
|
197
207
|
const isCategoryMoving = ref<boolean>(false);
|
|
198
208
|
|
|
199
|
-
function
|
|
209
|
+
function startMoveCategory(categoryId: number, direction: 'up' | 'down') {
|
|
200
210
|
isCategoryMoving.value = true;
|
|
201
211
|
|
|
202
|
-
|
|
212
|
+
moveCategory(categoryId, direction)
|
|
203
213
|
.then((response) => {
|
|
204
214
|
if (response.success) {
|
|
205
215
|
return fetchCategoryList();
|
|
@@ -222,7 +232,11 @@ export default defineComponent({
|
|
|
222
232
|
);
|
|
223
233
|
|
|
224
234
|
const columnDefs = computed(() =>
|
|
225
|
-
getCategoryTableColumnDefs(
|
|
235
|
+
getCategoryTableColumnDefs(
|
|
236
|
+
moduleConfig.value,
|
|
237
|
+
context.root.$t,
|
|
238
|
+
canViewAdministrators.value
|
|
239
|
+
)
|
|
226
240
|
);
|
|
227
241
|
|
|
228
242
|
return {
|
|
@@ -235,7 +249,7 @@ export default defineComponent({
|
|
|
235
249
|
isDeleting,
|
|
236
250
|
getBlogCategoryFormUrl,
|
|
237
251
|
getLinkToPostsByCategory,
|
|
238
|
-
|
|
252
|
+
startMoveCategory,
|
|
239
253
|
isCategoryMoving,
|
|
240
254
|
|
|
241
255
|
searchQuery,
|
|
@@ -248,6 +262,9 @@ export default defineComponent({
|
|
|
248
262
|
languageOptionList,
|
|
249
263
|
tags,
|
|
250
264
|
tagRemovalHandler,
|
|
265
|
+
|
|
266
|
+
// Permissions
|
|
267
|
+
canViewAdministrators,
|
|
251
268
|
};
|
|
252
269
|
},
|
|
253
270
|
});
|
package/src/views/Home.vue
CHANGED
|
@@ -7,7 +7,7 @@ import { defineComponent, ref } from '@vue/composition-api';
|
|
|
7
7
|
|
|
8
8
|
import { NavigationGridItem } from '@tager/admin-ui';
|
|
9
9
|
|
|
10
|
-
import { getBlogCategoryListUrl, getBlogPostListUrl } from '
|
|
10
|
+
import { getBlogCategoryListUrl, getBlogPostListUrl } from '@/constants/paths';
|
|
11
11
|
|
|
12
12
|
export default defineComponent({
|
|
13
13
|
name: 'Home',
|
|
@@ -6,11 +6,9 @@ import {
|
|
|
6
6
|
universalFieldUtils,
|
|
7
7
|
} from '@tager/admin-dynamic-field';
|
|
8
8
|
|
|
9
|
-
import { Category, PostFull } from '
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
PostUpdatePayload,
|
|
13
|
-
} from '../../../services/requests';
|
|
9
|
+
import { Category, PostFull } from '@/typings/model';
|
|
10
|
+
import { PostCreationPayload, PostUpdatePayload } from '@/services/requests';
|
|
11
|
+
import { getNameWithDepth } from '@/utils/common';
|
|
14
12
|
|
|
15
13
|
export interface FormValues {
|
|
16
14
|
title: string;
|
|
@@ -149,5 +147,8 @@ export function convertCategoryListToOptions(
|
|
|
149
147
|
): OptionType<number>[] {
|
|
150
148
|
return categoryList
|
|
151
149
|
.filter(({ language }) => (languageId ? language === languageId : true))
|
|
152
|
-
.map(({ id, name }) => ({
|
|
150
|
+
.map(({ id, name, depth }) => ({
|
|
151
|
+
value: id,
|
|
152
|
+
label: getNameWithDepth(name, depth),
|
|
153
|
+
}));
|
|
153
154
|
}
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
id="urlAlias"
|
|
40
40
|
v-model="values.urlAlias"
|
|
41
41
|
name="urlAlias"
|
|
42
|
-
:label="$t('blog:
|
|
42
|
+
:label="$t('blog:link')"
|
|
43
43
|
:url-template="urlAliasTemplate"
|
|
44
44
|
:error="errors.urlAlias"
|
|
45
45
|
@change="handleAliasChange"
|
|
@@ -111,11 +111,12 @@
|
|
|
111
111
|
/>
|
|
112
112
|
|
|
113
113
|
<form-field-multi-select
|
|
114
|
-
|
|
114
|
+
:selected-options="values.categories"
|
|
115
115
|
name="categories"
|
|
116
116
|
:label="$t('blog:categories')"
|
|
117
117
|
:options="categoryOptionList"
|
|
118
118
|
:error="errors.categories"
|
|
119
|
+
@change="handleCategoriesChange"
|
|
119
120
|
/>
|
|
120
121
|
|
|
121
122
|
<form-field-multi-select
|
|
@@ -195,20 +196,14 @@ import {
|
|
|
195
196
|
} from '@tager/admin-ui';
|
|
196
197
|
import { DynamicField } from '@tager/admin-dynamic-field';
|
|
197
198
|
|
|
199
|
+
import { createBlogPost, getPost, updateBlogPost } from '@/services/requests';
|
|
200
|
+
import { Language, PostFull } from '@/typings/model';
|
|
201
|
+
import { getBlogPostFormUrl, getBlogPostListUrl } from '@/constants/paths';
|
|
202
|
+
|
|
198
203
|
import {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
} from '../../../services/requests';
|
|
203
|
-
import { Language, PostFull } from '../../../typings/model';
|
|
204
|
-
import {
|
|
205
|
-
getBlogPostFormUrl,
|
|
206
|
-
getBlogPostListUrl,
|
|
207
|
-
} from '../../../constants/paths';
|
|
208
|
-
import {
|
|
209
|
-
useModuleConfig,
|
|
210
|
-
useBlogCategoryList,
|
|
211
|
-
useBlogPostList,
|
|
204
|
+
useFetchModuleConfig,
|
|
205
|
+
useFetchCategories,
|
|
206
|
+
useFetchPosts,
|
|
212
207
|
} from '../../../hooks';
|
|
213
208
|
|
|
214
209
|
import {
|
|
@@ -228,11 +223,12 @@ export default defineComponent({
|
|
|
228
223
|
|
|
229
224
|
const urlAliasChanged = ref<boolean>(false);
|
|
230
225
|
|
|
231
|
-
/** Fetch module config
|
|
226
|
+
/** Fetch module config **/
|
|
227
|
+
|
|
232
228
|
const {
|
|
233
229
|
data: moduleConfig,
|
|
234
230
|
loading: isModuleConfigLoading,
|
|
235
|
-
} =
|
|
231
|
+
} = useFetchModuleConfig({ context });
|
|
236
232
|
|
|
237
233
|
const languageList = computed<Language[]>(
|
|
238
234
|
() => moduleConfig.value?.languages ?? []
|
|
@@ -248,17 +244,18 @@ export default defineComponent({
|
|
|
248
244
|
const isLangSpecific = computed(() => languageOptionList.value.length > 0);
|
|
249
245
|
|
|
250
246
|
/** Fetch category list */
|
|
247
|
+
|
|
251
248
|
const {
|
|
252
249
|
data: categoryList,
|
|
253
250
|
loading: isCategoryListLoading,
|
|
254
|
-
} =
|
|
251
|
+
} = useFetchCategories({ context });
|
|
255
252
|
|
|
256
253
|
/** Fetch Post */
|
|
257
254
|
|
|
258
255
|
const [fetchPost, { data: post, loading: isPostLoading }] = useResource<
|
|
259
256
|
Nullable<PostFull>
|
|
260
257
|
>({
|
|
261
|
-
fetchResource: () =>
|
|
258
|
+
fetchResource: () => getPost(postId.value),
|
|
262
259
|
initialValue: null,
|
|
263
260
|
context,
|
|
264
261
|
resourceName: 'Post',
|
|
@@ -277,7 +274,7 @@ export default defineComponent({
|
|
|
277
274
|
});
|
|
278
275
|
|
|
279
276
|
/** Fetch post list */
|
|
280
|
-
const { data: postList, loading: isPostListLoading } =
|
|
277
|
+
const { data: postList, loading: isPostListLoading } = useFetchPosts({
|
|
281
278
|
context,
|
|
282
279
|
});
|
|
283
280
|
|
|
@@ -290,7 +287,8 @@ export default defineComponent({
|
|
|
290
287
|
}))
|
|
291
288
|
);
|
|
292
289
|
|
|
293
|
-
/** Form State
|
|
290
|
+
/** Form State **/
|
|
291
|
+
const isSubmitting = ref<boolean>(false);
|
|
294
292
|
const values = ref<FormValues>(
|
|
295
293
|
convertPostToFormValues(
|
|
296
294
|
post.value,
|
|
@@ -300,7 +298,6 @@ export default defineComponent({
|
|
|
300
298
|
)
|
|
301
299
|
);
|
|
302
300
|
const errors = ref<Record<string, string>>({});
|
|
303
|
-
const isSubmitting = ref<boolean>(false);
|
|
304
301
|
|
|
305
302
|
watch([post, languageOptionList, postOptionList, moduleConfig], () => {
|
|
306
303
|
values.value = convertPostToFormValues(
|
|
@@ -523,6 +520,43 @@ export default defineComponent({
|
|
|
523
520
|
return result;
|
|
524
521
|
});
|
|
525
522
|
|
|
523
|
+
const handleCategoriesChange = (selectedOptions: OptionType<number>[]) => {
|
|
524
|
+
const newSelectedOptions: OptionType<number>[] = [];
|
|
525
|
+
|
|
526
|
+
selectedOptions.forEach((selectedOption) => {
|
|
527
|
+
const findTreeSelectedCategory = (categoryId: number) => {
|
|
528
|
+
const foundSelectedCategory = categoryList.value.find(
|
|
529
|
+
({ id }) => id === categoryId
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
if (!foundSelectedCategory) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const newSelectedOption: OptionType<number> = {
|
|
537
|
+
value: foundSelectedCategory.id,
|
|
538
|
+
label: foundSelectedCategory.name,
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
if (
|
|
542
|
+
!newSelectedOptions.some(
|
|
543
|
+
({ value }) => value === newSelectedOption.value
|
|
544
|
+
)
|
|
545
|
+
) {
|
|
546
|
+
newSelectedOptions.push(newSelectedOption);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (foundSelectedCategory.parent) {
|
|
550
|
+
findTreeSelectedCategory(foundSelectedCategory.parent.id);
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
findTreeSelectedCategory(selectedOption.value);
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
values.value.categories = newSelectedOptions;
|
|
558
|
+
};
|
|
559
|
+
|
|
526
560
|
return {
|
|
527
561
|
isCreation,
|
|
528
562
|
postId,
|
|
@@ -546,6 +580,7 @@ export default defineComponent({
|
|
|
546
580
|
handleTitleChange,
|
|
547
581
|
handleAliasChange,
|
|
548
582
|
urlAliasTemplate,
|
|
583
|
+
handleCategoriesChange,
|
|
549
584
|
};
|
|
550
585
|
},
|
|
551
586
|
});
|
|
@@ -3,13 +3,8 @@ import { TFunction } from 'i18next';
|
|
|
3
3
|
import { notEmpty, Nullable } from '@tager/admin-services';
|
|
4
4
|
import { ColumnDefinition } from '@tager/admin-ui';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
ModuleConfig,
|
|
9
|
-
Language,
|
|
10
|
-
PostShort,
|
|
11
|
-
} from '../../../typings/model';
|
|
12
|
-
import { getBlogPostFormUrl } from '../../../constants/paths';
|
|
6
|
+
import { Category, ModuleConfig, Language, PostShort } from '@/typings/model';
|
|
7
|
+
import { getBlogPostFormUrl } from '@/constants/paths';
|
|
13
8
|
|
|
14
9
|
export function convertPostList(
|
|
15
10
|
postList: PostShort[],
|
|
@@ -38,7 +33,8 @@ export function convertPostList(
|
|
|
38
33
|
|
|
39
34
|
export function getPostTableColumnDefs(
|
|
40
35
|
moduleConfig: Nullable<ModuleConfig>,
|
|
41
|
-
t: TFunction
|
|
36
|
+
t: TFunction,
|
|
37
|
+
canViewAdministrators: boolean
|
|
42
38
|
): ColumnDefinition<PostShort>[] {
|
|
43
39
|
const isLangSpecific = moduleConfig
|
|
44
40
|
? moduleConfig.languages.length > 0
|
|
@@ -90,13 +86,15 @@ export function getPostTableColumnDefs(
|
|
|
90
86
|
format: ({ row }) =>
|
|
91
87
|
row.categories.map((category) => category.name).join(', '),
|
|
92
88
|
},
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
89
|
+
canViewAdministrators
|
|
90
|
+
? {
|
|
91
|
+
id: 7,
|
|
92
|
+
name: t('blog:actions'),
|
|
93
|
+
field: 'actions',
|
|
94
|
+
style: { whiteSpace: 'nowrap', width: '120px' },
|
|
95
|
+
headStyle: { whiteSpace: 'nowrap', width: '120px' },
|
|
96
|
+
}
|
|
97
|
+
: null,
|
|
100
98
|
];
|
|
101
99
|
|
|
102
100
|
return COLUMN_DEFS.filter(notEmpty);
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<page
|
|
3
3
|
:title="pageTitle"
|
|
4
|
-
:header-buttons="
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
:header-buttons="
|
|
5
|
+
[
|
|
6
|
+
canViewAdministrators
|
|
7
|
+
? {
|
|
8
|
+
text: $t('blog:newPost'),
|
|
9
|
+
href: getBlogPostFormUrl({ postId: 'create' }),
|
|
10
|
+
}
|
|
11
|
+
: null,
|
|
12
|
+
].filter(Boolean)
|
|
13
|
+
"
|
|
10
14
|
>
|
|
11
15
|
<template v-slot:content>
|
|
12
16
|
<data-table
|
|
@@ -77,18 +81,28 @@
|
|
|
77
81
|
<base-button
|
|
78
82
|
variant="icon"
|
|
79
83
|
:title="$t('blog:edit')"
|
|
80
|
-
:disabled="
|
|
84
|
+
:disabled="isBusy(row.id)"
|
|
81
85
|
:href="getBlogPostFormUrl({ postId: row.id })"
|
|
82
86
|
>
|
|
83
|
-
<svg-icon name="edit"
|
|
87
|
+
<svg-icon name="edit" />
|
|
84
88
|
</base-button>
|
|
89
|
+
|
|
90
|
+
<base-button
|
|
91
|
+
variant="icon"
|
|
92
|
+
:title="$t('blog:clone')"
|
|
93
|
+
:disabled="isBusy(row.id)"
|
|
94
|
+
@click="handleResourceClone(row.id)"
|
|
95
|
+
>
|
|
96
|
+
<svg-icon name="contentCopy" />
|
|
97
|
+
</base-button>
|
|
98
|
+
|
|
85
99
|
<base-button
|
|
86
100
|
variant="icon"
|
|
87
101
|
:title="$t('blog:remove')"
|
|
88
|
-
:disabled="
|
|
102
|
+
:disabled="isBusy(row.id)"
|
|
89
103
|
@click="handleResourceDelete(row.id)"
|
|
90
104
|
>
|
|
91
|
-
<svg-icon name="delete"
|
|
105
|
+
<svg-icon name="delete" />
|
|
92
106
|
</base-button>
|
|
93
107
|
</template>
|
|
94
108
|
</data-table>
|
|
@@ -99,42 +113,65 @@
|
|
|
99
113
|
<script lang="ts">
|
|
100
114
|
import { computed, defineComponent, watch } from '@vue/composition-api';
|
|
101
115
|
import isEqual from 'lodash.isequal';
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
import {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
import {
|
|
116
|
+
import pick from 'lodash.pick';
|
|
117
|
+
|
|
118
|
+
import {
|
|
119
|
+
ColumnDefinition,
|
|
120
|
+
useDataTable,
|
|
121
|
+
useTranslation,
|
|
122
|
+
} from '@tager/admin-ui';
|
|
123
|
+
import {
|
|
124
|
+
Nullable,
|
|
125
|
+
useResourceClone,
|
|
126
|
+
useResourceDelete,
|
|
127
|
+
} from '@tager/admin-services';
|
|
128
|
+
|
|
129
|
+
import { Category, Language, PostFull, PostShort } from '@/typings/model';
|
|
130
|
+
import { clonePost, deleteBlogPost, getPosts } from '@/services/requests';
|
|
131
|
+
import { getBlogPostFormUrl } from '@/constants/paths';
|
|
132
|
+
import {
|
|
133
|
+
useFetchModuleConfig,
|
|
134
|
+
useFetchCategories,
|
|
135
|
+
useUserPermission,
|
|
136
|
+
} from '@/hooks';
|
|
137
|
+
import { Scope } from '@/constants/scopes';
|
|
110
138
|
|
|
111
139
|
import { convertPostList, getPostTableColumnDefs } from './PostList.helpers';
|
|
112
140
|
import { useAdvancedSearch } from './hooks';
|
|
113
141
|
|
|
114
142
|
export default defineComponent({
|
|
115
|
-
name: '
|
|
143
|
+
name: 'Posts',
|
|
116
144
|
setup(props, context) {
|
|
145
|
+
const { t } = useTranslation(context);
|
|
146
|
+
|
|
147
|
+
const canViewAdministrators = useUserPermission(
|
|
148
|
+
context,
|
|
149
|
+
Scope.AdministratorsView
|
|
150
|
+
);
|
|
151
|
+
|
|
117
152
|
const categoryId = computed<string>(() => {
|
|
118
153
|
return Array.isArray(context.root.$route.query.category)
|
|
119
154
|
? context.root.$route.query.category[0] ?? ''
|
|
120
155
|
: context.root.$route.query.category;
|
|
121
156
|
});
|
|
122
157
|
|
|
123
|
-
/** Fetch module config
|
|
158
|
+
/** Fetch module config **/
|
|
159
|
+
|
|
124
160
|
const {
|
|
125
161
|
data: moduleConfig,
|
|
126
162
|
loading: isModuleConfigLoading,
|
|
127
|
-
} =
|
|
163
|
+
} = useFetchModuleConfig({ context });
|
|
128
164
|
|
|
129
165
|
const languageList = computed<Language[]>(
|
|
130
166
|
() => moduleConfig.value?.languages ?? []
|
|
131
167
|
);
|
|
132
168
|
|
|
133
|
-
/** Fetch category list
|
|
169
|
+
/** Fetch category list **/
|
|
170
|
+
|
|
134
171
|
const {
|
|
135
172
|
data: categoryList,
|
|
136
173
|
loading: isCategoryListLoading,
|
|
137
|
-
} =
|
|
174
|
+
} = useFetchCategories({ context });
|
|
138
175
|
|
|
139
176
|
const selectedCategory = computed<Nullable<Category>>(() =>
|
|
140
177
|
categoryId.value
|
|
@@ -174,7 +211,8 @@ export default defineComponent({
|
|
|
174
211
|
() => languageOptionList.value.length > 1
|
|
175
212
|
);
|
|
176
213
|
|
|
177
|
-
/** Fetch Post list
|
|
214
|
+
/** Fetch Post list **/
|
|
215
|
+
|
|
178
216
|
const {
|
|
179
217
|
fetchEntityList: fetchPostList,
|
|
180
218
|
isLoading: isPostLoading,
|
|
@@ -187,7 +225,7 @@ export default defineComponent({
|
|
|
187
225
|
pageSize,
|
|
188
226
|
} = useDataTable<PostShort>({
|
|
189
227
|
fetchEntityList: (params) =>
|
|
190
|
-
|
|
228
|
+
getPosts({
|
|
191
229
|
query: params.searchQuery,
|
|
192
230
|
pageNumber: params.pageNumber,
|
|
193
231
|
pageSize: params.pageSize,
|
|
@@ -205,8 +243,8 @@ export default defineComponent({
|
|
|
205
243
|
}
|
|
206
244
|
|
|
207
245
|
const newQuery = {
|
|
246
|
+
...pick(context.root.$route.query, ['query', 'pageNumber']),
|
|
208
247
|
...filterParams.value,
|
|
209
|
-
query: (context.root.$route.query.query ?? '') as string,
|
|
210
248
|
};
|
|
211
249
|
|
|
212
250
|
if (!isEqual(context.root.$route.query, newQuery)) {
|
|
@@ -223,13 +261,6 @@ export default defineComponent({
|
|
|
223
261
|
)
|
|
224
262
|
);
|
|
225
263
|
|
|
226
|
-
const { handleResourceDelete, isDeleting } = useResourceDelete({
|
|
227
|
-
deleteResource: deleteBlogPost,
|
|
228
|
-
resourceName: 'Post',
|
|
229
|
-
onSuccess: fetchPostList,
|
|
230
|
-
context,
|
|
231
|
-
});
|
|
232
|
-
|
|
233
264
|
const isRowDataLoading = computed<boolean>(
|
|
234
265
|
() =>
|
|
235
266
|
isCategoryListLoading.value ||
|
|
@@ -237,8 +268,32 @@ export default defineComponent({
|
|
|
237
268
|
isModuleConfigLoading.value
|
|
238
269
|
);
|
|
239
270
|
|
|
271
|
+
const { isDeleting, handleResourceDelete } = useResourceDelete({
|
|
272
|
+
deleteResource: deleteBlogPost,
|
|
273
|
+
resourceName: 'Post',
|
|
274
|
+
onSuccess: fetchPostList,
|
|
275
|
+
context,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const { isCloning, handleResourceClone } = useResourceClone({
|
|
279
|
+
cloneResource: clonePost,
|
|
280
|
+
confirmMessage: t('blog:cloneConfirm'),
|
|
281
|
+
successMessage: t('blog:cloneSuccess'),
|
|
282
|
+
failureMessage: t('blog:cloneFailure'),
|
|
283
|
+
onSuccessRedirectTo: (data: PostFull) => `/posts/${data.id}`,
|
|
284
|
+
context,
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
function isBusy(postId: number): boolean {
|
|
288
|
+
return isDeleting(postId) || isCloning(postId) || isRowDataLoading.value;
|
|
289
|
+
}
|
|
290
|
+
|
|
240
291
|
const columnDefs = computed<ColumnDefinition<PostShort>[]>(() =>
|
|
241
|
-
getPostTableColumnDefs(
|
|
292
|
+
getPostTableColumnDefs(
|
|
293
|
+
moduleConfig.value,
|
|
294
|
+
context.root.$t,
|
|
295
|
+
canViewAdministrators.value
|
|
296
|
+
)
|
|
242
297
|
);
|
|
243
298
|
|
|
244
299
|
return {
|
|
@@ -267,6 +322,13 @@ export default defineComponent({
|
|
|
267
322
|
toDateFilter,
|
|
268
323
|
tags,
|
|
269
324
|
tagRemovalHandler,
|
|
325
|
+
|
|
326
|
+
// Permissions
|
|
327
|
+
canViewAdministrators,
|
|
328
|
+
|
|
329
|
+
// Clone
|
|
330
|
+
handleResourceClone,
|
|
331
|
+
isBusy,
|
|
270
332
|
};
|
|
271
333
|
},
|
|
272
334
|
});
|
|
@@ -16,7 +16,8 @@ import {
|
|
|
16
16
|
} from '@tager/admin-ui';
|
|
17
17
|
import { isNotNullish } from '@tager/admin-services';
|
|
18
18
|
|
|
19
|
-
import { Category, Language } from '
|
|
19
|
+
import { Category, Language } from '@/typings/model';
|
|
20
|
+
import { getNameWithDepth } from '@/utils/common';
|
|
20
21
|
|
|
21
22
|
interface Params {
|
|
22
23
|
context: SetupContext;
|
|
@@ -53,9 +54,9 @@ export function useAdvancedSearch({
|
|
|
53
54
|
/** Category **/
|
|
54
55
|
|
|
55
56
|
const categoryOptionList = computed<OptionType[]>(() =>
|
|
56
|
-
categoryList.value.map(({ id, name }) => ({
|
|
57
|
+
categoryList.value.map(({ id, name, depth }) => ({
|
|
57
58
|
value: String(id),
|
|
58
|
-
label: name,
|
|
59
|
+
label: getNameWithDepth(name, depth),
|
|
59
60
|
}))
|
|
60
61
|
);
|
|
61
62
|
|
|
@@ -229,9 +230,9 @@ export function useAdvancedSearch({
|
|
|
229
230
|
languageFilter.value.some(({ value }) => value === language)
|
|
230
231
|
);
|
|
231
232
|
|
|
232
|
-
return selectedList.map(({ id, name }) => ({
|
|
233
|
+
return selectedList.map(({ id, name, depth }) => ({
|
|
233
234
|
value: String(id),
|
|
234
|
-
label: name,
|
|
235
|
+
label: getNameWithDepth(name, depth),
|
|
235
236
|
}));
|
|
236
237
|
});
|
|
237
238
|
|