2021-12-18 20:10:02 +01:00
< script lang = "ts" >
2021-12-19 00:58:55 +01:00
import { Card , CardHeader , CardBody , CardTitle , Alert , Accordion , AccordionItem , InputGroupText , InputGroup , Input , Label , Row , Col , Spinner , Button , Tooltip } from 'sveltestrap';
2021-12-19 14:24:21 +01:00
import FaUsers from 'svelte-icons/fa/FaUsers.svelte'
2021-12-18 20:10:02 +01:00
import { onMount } from 'svelte';
import FaSearch from 'svelte-icons/fa/FaSearch.svelte'
import { useParams } from 'svelte-navigator';
import type Group from '../../api/group'
2021-12-19 00:58:55 +01:00
import type Member from '../../api/member'
2021-12-18 20:10:02 +01:00
import PKAPI from '../../api';
import CardsHeader from '../CardsHeader.svelte';
import ListPagination from '../ListPagination.svelte';
2021-12-19 00:58:55 +01:00
import Body from './Body.svelte';
import Svelecte, { addFormatter } from 'svelecte';
2021-12-19 14:24:21 +01:00
import FaLock from 'svelte-icons/fa/FaLock.svelte';
2021-12-18 20:10:02 +01:00
export let isPublic: boolean;
2021-12-19 00:58:55 +01:00
export let list: Group[];
export let members: Member[];
$: memberlist = members.map(function(member) { return { name : member.name , shortid : member.id , id : member.uuid , display_name : member.display_name }; } ).sort((a, b) => a.name.localeCompare(b.name));
2021-12-18 20:10:02 +01:00
let token = localStorage.getItem("pk-token");
let listLoading = true;
let err: string;
let itemsPerPageValue = "25";
$: itemsPerPage = parseInt(itemsPerPageValue);
let searchBy = "name";
let sortBy = "name";
let sortOrder = "ascending";
let privacyFilter = "all";
2021-12-19 00:58:55 +01:00
let memberSearchMode = "include";
let selectedMembers = [];
2021-12-18 20:10:02 +01:00
let currentPage = 1;
let params = useParams();
$: id = $params.id;
onMount(() => {
if (token || isPublic) fetchGroups();
});
const api = new PKAPI();
async function fetchGroups() {
listLoading = true;
try {
2021-12-19 00:58:55 +01:00
const res: Group[] = await api.getGroupList({ token : ! isPublic && token , id : isPublic && id , members : ! isPublic ? true : false } );
2021-12-18 20:10:02 +01:00
list = res;
listLoading = false;
} catch (error) {
console.log(error);
err = error.message;
listLoading = false;
}
}
let searchValue: string;
$: { searchValue ; privacyFilter ; currentPage = 1 } ;
$: searchedList = list.filter((item) => {
if (!searchValue) return true;
switch (searchBy) {
case "name": if (item.name.toLowerCase().includes(searchValue.toLowerCase())) return true;
break;
case "display name": if (item.display_name & & item.display_name.toLowerCase().includes(searchValue.toLowerCase())) return true;
break;
case "description": if (item.description & & item.description.toLowerCase().includes(searchValue.toLowerCase())) return true;
break;
case "ID": if (item.id.toLowerCase().includes(searchValue.toLowerCase())) return true;
break;
default: if (item.name.toLowerCase().includes(searchValue.toLowerCase())) return true;
break;
}
return false;
})
$: filteredList = searchedList.filter((item) => {
if (privacyFilter === "all") return true;
if (privacyFilter === "public" & & item.privacy.visibility === "public") return true;
if (privacyFilter === "private" & & item.privacy.visibility === "private") return true;
return false;
});
let sortedList = [];
$: if (filteredList) {
switch (sortBy) {
case "name": sortedList = filteredList.sort((a, b) => a.name.localeCompare(b.name));
break;
case "display name": sortedList = filteredList.sort((a, b) => {
if (a.display_name & & b.display_name) return a.display_name.localeCompare(b.display_name);
else if (a.display_name & & !b.display_name) return a.display_name.localeCompare(b.name);
else if (!a.display_name & & b.display_name) return a.name.localeCompare(b.display_name);
else return a.name.localeCompare(b.name);
});
break;
2021-12-19 15:19:43 +01:00
case "creation date": sortedList = filteredList.sort((a, b) => {
if (a.created & & b.created) return a.created.localeCompare(b.created);
});
2021-12-18 20:10:02 +01:00
break;
case "ID": sortedList = filteredList.sort((a, b) => a.id.localeCompare(b.id));
break;
default: sortedList = filteredList.sort((a, b) => a.name.localeCompare(b.name));
break;
}
}
2021-12-19 00:58:55 +01:00
let memberFilteredList = [];
$: memberFilteredList = sortedList.filter((item: Group) => {
2021-12-21 00:20:25 +01:00
if (memberSearchMode === "none") {
if (item.members & & item.members.length > 0) return false;
}
2021-12-19 00:58:55 +01:00
if (selectedMembers.length < 1 ) return true ;
switch (memberSearchMode) {
2021-12-21 00:20:25 +01:00
case "include": if (item.members & & selectedMembers.some(value => item.members.includes(value))) return true;
2021-12-19 00:58:55 +01:00
break;
2021-12-21 00:20:25 +01:00
case "exclude": if (item.members & & selectedMembers.every(value => !item.members.includes(value))) return true;
2021-12-19 00:58:55 +01:00
break;
2021-12-21 00:20:25 +01:00
case "match": if (item.members & & selectedMembers.every(value => item.members.includes(value))) return true;
2021-12-19 00:58:55 +01:00
break;
default: return true;
}
return false;
});
let finalList = [];
$:{ sortOrder ; if ( sortOrder === "descending" ) finalList = memberFilteredList . reverse (); else finalList = memberFilteredList ;}
$: finalList = finalList;
2021-12-18 20:10:02 +01:00
$: indexOfLastItem = currentPage * itemsPerPage;
$: indexOfFirstItem = indexOfLastItem - itemsPerPage;
2021-12-19 00:58:55 +01:00
$: pageAmount = Math.ceil(finalList.length / itemsPerPage);
2021-12-18 20:10:02 +01:00
2021-12-19 12:01:55 +01:00
let slicedList = [];
2021-12-19 00:58:55 +01:00
$: slicedList = finalList.slice(indexOfFirstItem, indexOfLastItem);
function memberListRenderer(item: any) {
return `${ item . name } (< code > ${ item . shortid } </ code > )`;
}
addFormatter({
'member-list': memberListRenderer
});
2021-12-18 20:10:02 +01:00
2021-12-19 09:53:13 +01:00
let itemLoading: boolean[] = [];
$: itemLoading.length = slicedList.length;
2021-12-19 12:01:55 +01:00
function updateList(event: any) {
list = list.map(group => group.id !== event.detail.id ? group : event.detail)
}
2021-12-18 20:10:02 +01:00
< / script >
< Card class = "mb-3" >
< CardHeader >
< CardTitle >
< CardTitle style = "margin-top: 8px; outline: none;" >
< div class = "icon d-inline-block" >
< FaSearch / >
< / div > Search groups
< / CardTitle >
< / CardTitle >
< / CardHeader >
< CardBody >
< Row >
< Col xs = { 12 } lg= { 3 } class = "mb-2" >
< InputGroup >
< InputGroupText > Page length< / InputGroupText >
< Input bind:value = { itemsPerPageValue } type="select" >
< option > 10< / option >
< option > 25< / option >
< option > 50< / option >
< / Input >
< / InputGroup >
< / Col >
< Col xs = { 12 } lg= { 3 } class = "mb-2" >
< InputGroup >
< InputGroupText > Search by< / InputGroupText >
< Input bind:value = { searchBy } type="select" >
< option > name< / option >
< option > display name< / option >
< option > description< / option >
< option > ID< / option >
< / Input >
< / InputGroup >
< / Col >
< Col xs = { 12 } lg= { 3 } class = "mb-2" >
< InputGroup >
< InputGroupText > Sort by< / InputGroupText >
< Input bind:value = { sortBy } type="select" >
< option > name< / option >
< option > display name< / option >
{ #if ! isPublic } < option > creation date</ option > { /if }
< option > ID< / option >
< / Input >
< / InputGroup >
< / Col >
< Col xs = { 12 } lg= { 3 } class = "mb-2" >
< InputGroup >
< InputGroupText > Sort order< / InputGroupText >
< Input bind:value = { sortOrder } type="select" >
< option > ascending< / option >
< option > descending< / option >
< / Input >
< / InputGroup >
< / Col >
{ #if ! isPublic }
2021-12-19 00:58:55 +01:00
< Col xs = { 12 } lg= { 3 } class = "mb-2" >
2021-12-18 20:10:02 +01:00
< InputGroup >
< InputGroupText > Only show< / InputGroupText >
< Input bind:value = { privacyFilter } type="select" >
< option > all< / option >
< option > public< / option >
< option > private< / option >
< / Input >
< / InputGroup >
< / Col >
{ /if }
< / Row >
2021-12-19 00:58:55 +01:00
{ #if ! isPublic }
< hr / >
< Label > Filter groups by member< / Label >
2021-12-21 00:21:46 +01:00
< Svelecte renderer = "member-list" bind:value = { selectedMembers } disableHighlight options = { memberlist } multiple style = "margin-bottom: 0.5rem" >
2021-12-19 00:58:55 +01:00
< / Svelecte >
< span style = "cursor: pointer" id = "include" on:click = {() => memberSearchMode = "include" } > { @html memberSearchMode === "include" ? "<b>include</b>" : "include" } </span >
| < span style = "cursor: pointer" id = "exclude" on:click = {() => memberSearchMode = "exclude" } > { @html memberSearchMode === "exclude" ? "<b>exclude</b>" : "exclude" } </span >
| < span style = "cursor: pointer" id = "match" on:click = {() => memberSearchMode = "match" } > { @html memberSearchMode === "match" ? "<b>exact match</b>" : "exact match" } </span >
2021-12-21 00:20:25 +01:00
| < span style = "cursor: pointer" id = "none" on:click = {() => memberSearchMode = "none" } > { @html memberSearchMode === "none" ? "<b>none</b>" : "none" } </span >
2021-12-19 00:58:55 +01:00
< Tooltip placement = "bottom" target = "include" > Includes every group with any of the members.< / Tooltip >
< Tooltip placement = "bottom" target = "exclude" > Excludes every group with any of the members, opposite of include.< / Tooltip >
< Tooltip placement = "bottom" target = "match" > Only includes groups which have all the members selected.< / Tooltip >
2021-12-21 00:20:25 +01:00
< Tooltip placement = "bottom" target = "none" > Only includes groups that have no members.< / Tooltip >
2021-12-19 00:58:55 +01:00
{ /if }
2021-12-18 20:10:02 +01:00
< / CardBody >
< / Card >
{ #if listLoading && ! err }
< div class = "mx-auto text-center" >
< Spinner class = "d-inline-block" / >
< / div >
{ :else if err }
< Alert color = "danger" > { err } </ Alert >
{ : else }
< Row >
< Col xs = { 12 } lg= { 10 } class = "mb-2 mb-lg-0" >
< Input class = "mb-3" bind:value = { searchValue } placeholder="search by { searchBy } ..." />
< / Col >
< Col xs = { 12 } lg= { 2 } >
2021-12-19 12:02:38 +01:00
< Button class = "w-100 mb-3" color = "primary" on:click = { fetchGroups } > Refresh</Button >
2021-12-18 20:10:02 +01:00
< / Col >
< / Row >
< ListPagination bind:currentPage bind:pageAmount / >
< Accordion class = "my-3" stayOpen >
2021-12-19 09:53:13 +01:00
{ #each slicedList as group , index ( group . id )}
2021-12-19 14:24:21 +01:00
{ #if ( ! isPublic && group . privacy . visibility === "public" ) || isPublic }
2021-12-18 20:10:02 +01:00
< AccordionItem >
2021-12-19 14:24:21 +01:00
< CardsHeader bind:item = { group } loading= { itemLoading [ index ]} slot = "header" >
< FaUsers slot = "icon" / >
2021-12-18 20:10:02 +01:00
< / CardsHeader >
2021-12-21 00:20:25 +01:00
< Body on:update = { updateList } bind:members bind:group bind:isPublic = { isPublic } bind:loading= { itemLoading [ index ]} / >
2021-12-18 20:10:02 +01:00
< / AccordionItem >
2021-12-19 14:24:21 +01:00
{ : else }
< AccordionItem >
< CardsHeader bind:item = { group } loading= { itemLoading [ index ]} slot = "header" >
< FaLock slot = "icon" / >
< / CardsHeader >
2021-12-21 00:20:25 +01:00
< Body on:update = { updateList } bind:members bind:group bind:isPublic = { isPublic } bind:loading= { itemLoading [ index ]} / >
2021-12-19 14:24:21 +01:00
< / AccordionItem >
{ /if }
2021-12-18 20:10:02 +01:00
{ /each }
< / Accordion >
< ListPagination bind:currentPage bind:pageAmount / >
{ /if }