@@ -10,29 +10,18 @@ import {
1010} from ' @/api' ;
1111import { dialogProps } from ' @/common' ;
1212import HelpButtonWidget from ' @/components/HelpButtonWidget.vue' ;
13- import LabeledSwitch from ' @/components/LabeledSwitch .vue' ;
13+ import ListingsFilters from ' @/components/ListingsFilters .vue' ;
1414import IconHeading from ' @/components/generic/IconHeading.vue' ;
1515import TransferResourceModal from ' @/components/modals/TransferResourceModal.vue' ;
1616import ResourceListItem from ' @/components/resource/ResourceListItem.vue' ;
1717import { useMessages } from ' @/composables/messages' ;
1818import { useTasks } from ' @/composables/tasks' ;
1919import { $t } from ' @/i18n' ;
20- import { AddIcon , FilterIcon , ResourceIcon , SearchIcon , UndoIcon } from ' @/icons' ;
20+ import { AddIcon , ResourceIcon } from ' @/icons' ;
2121import { useAuthStore , useResourcesStore , useStateStore , useUserMessagesStore } from ' @/stores' ;
2222import { pickTranslation } from ' @/utils' ;
2323import { createReusableTemplate } from ' @vueuse/core' ;
24- import {
25- NButton ,
26- NCollapse ,
27- NCollapseItem ,
28- NFlex ,
29- NIcon ,
30- NInput ,
31- NList ,
32- NPagination ,
33- NSpin ,
34- useDialog ,
35- } from ' naive-ui' ;
24+ import { NButton , NFlex , NIcon , NList , NPagination , NSpin , useDialog } from ' naive-ui' ;
3625import { computed , onMounted , ref } from ' vue' ;
3726import { useRouter } from ' vue-router' ;
3827
@@ -61,44 +50,38 @@ const pagination = ref({
6150 pageSize: 20 ,
6251});
6352
64- const initialFilters = () => ({
65- search: ' ' ,
66- public: true ,
67- notPublic: true ,
68- proposed: true ,
69- notProposed: true ,
70- ownedByMe: true ,
71- ownedByOthers: true ,
72- hasCorrections: true ,
73- hasNoCorrections: true ,
74- });
75-
76- const filters = ref (initialFilters ());
53+ const filtersRef = ref <InstanceType <typeof ListingsFilters > | null >(null );
54+ const filtersSearch = ref <string >();
55+ const filtersFlags = ref <string []>();
7756
7857function filterData(resourcesData : AnyResourceRead []) {
7958 pagination .value .page = 1 ;
8059 return resourcesData .filter ((r ) => {
81- const resourceStringContent = filters .value . search
60+ const resourceStringContent = filtersSearch .value
8261 ? [
8362 r .title .map ((t ) => t .translation ).join (' ' ),
8463 r .subtitle .map ((s ) => s .translation ).join (' ' ) || ' ' ,
85- r .ownerId ,
64+ r .owner ?.name || ' ' ,
65+ r .owner ?.username || ' ' ,
66+ r .owner ?.affiliation || ' ' ,
8667 r .description .map ((d ) => d .translation ).join (' ' ) || ' ' ,
8768 r .citation ,
8869 JSON .stringify (r .meta ),
8970 ]
90- .filter (( prop ) => prop )
71+ .filter (Boolean )
9172 .join (' ' )
9273 : ' ' ;
9374 return (
94- (! filters .value .search ||
95- resourceStringContent .toLowerCase ().includes (filters .value .search .toLowerCase ())) &&
96- ((filters .value .proposed && r .proposed ) || (filters .value .notProposed && ! r .proposed )) &&
97- ((filters .value .public && r .public ) || (filters .value .notPublic && ! r .public )) &&
98- ((filters .value .ownedByMe && r .ownerId === auth .user ?.id ) ||
99- (filters .value .ownedByOthers && r .ownerId !== auth .user ?.id )) &&
100- ((filters .value .hasCorrections && r .corrections ) ||
101- (filters .value .hasNoCorrections && ! r .corrections ))
75+ (! filtersSearch .value ||
76+ resourceStringContent .toLowerCase ().includes (filtersSearch .value .toLowerCase ())) &&
77+ ((filtersFlags .value ?.includes (' proposed' ) && r .proposed ) ||
78+ (filtersFlags .value ?.includes (' notProposed' ) && ! r .proposed )) &&
79+ ((filtersFlags .value ?.includes (' public' ) && r .public ) ||
80+ (filtersFlags .value ?.includes (' notPublic' ) && ! r .public )) &&
81+ ((filtersFlags .value ?.includes (' ownedByMe' ) && r .ownerId === auth .user ?.id ) ||
82+ (filtersFlags .value ?.includes (' notOwnedByMe' ) && r .ownerId !== auth .user ?.id )) &&
83+ ((filtersFlags .value ?.includes (' hasCorrections' ) && r .corrections ) ||
84+ (filtersFlags .value ?.includes (' hasNoCorrections' ) && ! r .corrections ))
10285 );
10386 });
10487}
@@ -146,7 +129,7 @@ async function handleTransferResource(resource?: AnyResourceRead, user?: UserRea
146129 })
147130 );
148131 }
149- filters .value = initialFilters ();
132+ filtersRef .value ?. reset ();
150133 showTransferModal .value = false ;
151134 transferTargetResource .value = undefined ;
152135 actionsLoading .value = false ;
@@ -171,7 +154,7 @@ function handleProposeClick(resource: AnyResourceRead) {
171154 $t (' resources.msgProposed' , { title: pickTranslation (resource .title , state .locale ) })
172155 );
173156 }
174- filters .value = initialFilters ();
157+ filtersRef .value ?. reset ();
175158 actionsLoading .value = false ;
176159 },
177160 });
@@ -196,7 +179,7 @@ function handleUnproposeClick(resource: AnyResourceRead) {
196179 $t (' resources.msgUnproposed' , { title: pickTranslation (resource .title , state .locale ) })
197180 );
198181 }
199- filters .value = initialFilters ();
182+ filtersRef .value ?. reset ();
200183 actionsLoading .value = false ;
201184 },
202185 });
@@ -221,7 +204,7 @@ function handlePublishClick(resource: AnyResourceRead) {
221204 $t (' resources.msgPublished' , { title: pickTranslation (resource .title , state .locale ) })
222205 );
223206 }
224- filters .value = initialFilters ();
207+ filtersRef .value ?. reset ();
225208 actionsLoading .value = false ;
226209 },
227210 });
@@ -246,7 +229,7 @@ function handleUnpublishClick(resource: AnyResourceRead) {
246229 $t (' resources.msgUnpublished' , { title: pickTranslation (resource .title , state .locale ) })
247230 );
248231 }
249- filters .value = initialFilters ();
232+ filtersRef .value ?. reset ();
250233 actionsLoading .value = false ;
251234 },
252235 });
@@ -376,12 +359,6 @@ function handleReqVersionIntegrationClick(resourceVersion: AnyResourceRead) {
376359 userMessages .openConversation (originalResource .ownerId , prepMsg );
377360}
378361
379- function handleFilterCollapseItemClick(data : { name: string ; expanded: boolean }) {
380- if (data .name === ' filters' && ! data .expanded ) {
381- filters .value = initialFilters ();
382- }
383- }
384-
385362onMounted (() => {
386363 // inform user in case there are corrections for resources of another text
387364 if (
@@ -416,51 +393,24 @@ onMounted(() => {
416393
417394 <template v-if =" resources .ofText && ! resources .error && ! loading " >
418395 <!-- Filters -->
419- <n-collapse class =" mb-lg" @item-header-click =" handleFilterCollapseItemClick" >
420- <n-collapse-item name =" filters" >
421- <template #header >
422- <n-flex align =" center" :wrap =" false" >
423- <n-icon :component =" FilterIcon" class =" translucent" />
424- <span >{{ $t('common.filters') }}</span >
425- </n-flex >
426- </template >
427-
428- <n-flex vertical size =" small" class =" gray-box" >
429- <n-input
430- v-model:value =" filters.search"
431- :placeholder =" $t('common.searchAction')"
432- class =" mb-md"
433- round
434- >
435- <template #prefix >
436- <n-icon :component =" SearchIcon" />
437- </template >
438- </n-input >
439- <labeled-switch v-model =" filters.public" :label =" $t('resources.public')" />
440- <labeled-switch v-model =" filters.notPublic" :label =" $t('resources.notPublic')" />
441- <labeled-switch v-model =" filters.proposed" :label =" $t('resources.proposed')" />
442- <labeled-switch v-model =" filters.notProposed" :label =" $t('resources.notProposed')" />
443- <labeled-switch v-model =" filters.ownedByMe" :label =" $t('resources.ownedByMe')" />
444- <labeled-switch v-model =" filters.ownedByOthers" :label =" $t('resources.ownedByOthers')" />
445- <labeled-switch
446- v-model =" filters.hasCorrections"
447- :label =" $t('resources.hasCorrections')"
448- />
449- <labeled-switch
450- v-model =" filters.hasNoCorrections"
451- :label =" $t('resources.hasNoCorrections')"
452- />
453- <n-button secondary class =" mt-md" @click =" filters = initialFilters()" >
454- {{ $t('common.reset') }}
455- <template #icon >
456- <n-icon :component =" UndoIcon" />
457- </template >
458- </n-button >
459- </n-flex >
460- </n-collapse-item >
461- </n-collapse >
462-
463- <div class =" resource-list-header" >
396+ <listings-filters
397+ ref =" filtersRef"
398+ v-model:search =" filtersSearch"
399+ v-model:flags =" filtersFlags"
400+ :flags-labels =" {
401+ public: $t('resources.public'),
402+ notPublic: $t('resources.notPublic'),
403+ proposed: $t('resources.proposed'),
404+ notProposed: $t('resources.notProposed'),
405+ ownedByMe: $t('resources.ownedByMe'),
406+ ownedByOthers: $t('resources.ownedByOthers'),
407+ hasCorrections: $t('resources.hasCorrections'),
408+ hasNoCorrections: $t('resources.hasNoCorrections'),
409+ }"
410+ />
411+
412+ <!-- List Header -->
413+ <n-flex justify =" space-between" align =" center" >
464414 <div class =" text-small translucent ellipsis" >
465415 {{
466416 $t('resources.msgFoundCount', {
@@ -480,7 +430,7 @@ onMounted(() => {
480430 </template >
481431 {{ $t('resources.new') }}
482432 </n-button >
483- </div >
433+ </n-flex >
484434
485435 <!-- Resources List -->
486436 <div class =" content-block" >
@@ -532,14 +482,6 @@ onMounted(() => {
532482</template >
533483
534484<style scoped>
535- .resource-list-header {
536- display : flex ;
537- justify-content : space-between ;
538- flex-wrap : nowrap ;
539- align-items : flex-end ;
540- max-width : 100% ;
541- }
542-
543485.pagination-container :first-child {
544486 margin-bottom : var (--gap-lg );
545487}
0 commit comments