2020-08-27 11:53:24 +02:00
|
|
|
<template>
|
|
|
|
<div>
|
2022-01-10 15:19:16 +01:00
|
|
|
<breadcrumbs-nav
|
|
|
|
:links="[
|
2022-08-26 16:08:58 +02:00
|
|
|
{ name: RouteName.MODERATION, text: t('Moderation') },
|
2022-01-10 15:19:16 +01:00
|
|
|
{
|
|
|
|
name: RouteName.ADMIN_GROUPS,
|
2022-08-26 16:08:58 +02:00
|
|
|
text: t('Groups'),
|
2022-01-10 15:19:16 +01:00
|
|
|
},
|
|
|
|
]"
|
|
|
|
/>
|
2021-10-06 18:00:50 +02:00
|
|
|
<div class="buttons" v-if="showCreateGroupsButton">
|
|
|
|
<router-link
|
|
|
|
class="button is-primary"
|
|
|
|
:to="{ name: RouteName.CREATE_GROUP }"
|
2022-08-26 16:08:58 +02:00
|
|
|
>{{ t("Create group") }}</router-link
|
2021-10-06 18:00:50 +02:00
|
|
|
>
|
|
|
|
</div>
|
2020-08-27 11:53:24 +02:00
|
|
|
<div v-if="groups">
|
2022-07-12 10:55:28 +02:00
|
|
|
<div class="flex gap-2">
|
2022-08-26 16:08:58 +02:00
|
|
|
<o-switch v-model="local">{{ t("Local") }}</o-switch>
|
|
|
|
<o-switch v-model="suspended">{{ t("Suspended") }}</o-switch>
|
2022-07-12 10:55:28 +02:00
|
|
|
</div>
|
|
|
|
<o-table
|
2020-08-27 11:53:24 +02:00
|
|
|
:data="groups.elements"
|
2022-07-12 10:55:28 +02:00
|
|
|
:loading="loading"
|
2020-08-27 11:53:24 +02:00
|
|
|
paginated
|
|
|
|
backend-pagination
|
|
|
|
backend-filtering
|
2021-05-12 18:10:07 +02:00
|
|
|
:debounce-search="200"
|
2022-07-12 10:55:28 +02:00
|
|
|
v-model:current-page="page"
|
2022-08-26 16:08:58 +02:00
|
|
|
:aria-next-label="t('Next page')"
|
|
|
|
:aria-previous-label="t('Previous page')"
|
|
|
|
:aria-page-label="t('Page')"
|
|
|
|
:aria-current-label="t('Current page')"
|
2020-08-27 11:53:24 +02:00
|
|
|
:total="groups.total"
|
|
|
|
:per-page="PROFILES_PER_PAGE"
|
|
|
|
@page-change="onPageChange"
|
|
|
|
@filters-change="onFiltersChange"
|
|
|
|
>
|
2022-07-12 10:55:28 +02:00
|
|
|
<o-table-column
|
2020-11-30 10:24:11 +01:00
|
|
|
field="preferredUsername"
|
2022-08-26 16:08:58 +02:00
|
|
|
:label="t('Username')"
|
2020-11-30 10:24:11 +01:00
|
|
|
searchable
|
|
|
|
>
|
2021-04-16 18:13:17 +02:00
|
|
|
<template #searchable="props">
|
2022-07-12 10:55:28 +02:00
|
|
|
<o-input
|
2022-08-26 16:08:58 +02:00
|
|
|
:aria-label="t('Filter')"
|
2020-08-27 11:53:24 +02:00
|
|
|
v-model="props.filters.preferredUsername"
|
2022-08-26 16:08:58 +02:00
|
|
|
:placeholder="t('Filter')"
|
2020-08-27 11:53:24 +02:00
|
|
|
icon="magnify"
|
|
|
|
/>
|
|
|
|
</template>
|
2022-08-12 16:42:40 +02:00
|
|
|
<template #default="props">
|
2020-08-27 11:53:24 +02:00
|
|
|
<router-link
|
|
|
|
class="profile"
|
2020-11-30 10:24:11 +01:00
|
|
|
:to="{
|
|
|
|
name: RouteName.ADMIN_GROUP_PROFILE,
|
|
|
|
params: { id: props.row.id },
|
|
|
|
}"
|
2020-08-27 11:53:24 +02:00
|
|
|
>
|
2022-07-12 10:55:28 +02:00
|
|
|
<article class="flex gap-1">
|
|
|
|
<figure class="" v-if="props.row.avatar">
|
|
|
|
<img
|
|
|
|
:src="props.row.avatar.url"
|
|
|
|
:alt="props.row.avatar.alt || ''"
|
|
|
|
width="48"
|
|
|
|
height="48"
|
|
|
|
class="rounded-full"
|
|
|
|
/>
|
2020-08-27 11:53:24 +02:00
|
|
|
</figure>
|
2022-07-12 10:55:28 +02:00
|
|
|
<AccountGroup v-else :size="48" />
|
|
|
|
<div class="">
|
|
|
|
<div class="prose dark:prose-invert">
|
2020-08-27 11:53:24 +02:00
|
|
|
<strong v-if="props.row.name">{{ props.row.name }}</strong
|
|
|
|
><br v-if="props.row.name" />
|
|
|
|
<small>@{{ props.row.preferredUsername }}</small>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</article>
|
|
|
|
</router-link>
|
|
|
|
</template>
|
2022-07-12 10:55:28 +02:00
|
|
|
</o-table-column>
|
2020-08-27 11:53:24 +02:00
|
|
|
|
2022-08-26 16:08:58 +02:00
|
|
|
<o-table-column field="domain" :label="t('Domain')" searchable>
|
2021-04-16 18:13:17 +02:00
|
|
|
<template #searchable="props">
|
2022-07-12 10:55:28 +02:00
|
|
|
<o-input
|
2022-08-26 16:08:58 +02:00
|
|
|
:aria-label="t('Filter')"
|
2020-08-27 11:53:24 +02:00
|
|
|
v-model="props.filters.domain"
|
2022-08-26 16:08:58 +02:00
|
|
|
:placeholder="t('Filter')"
|
2020-08-27 11:53:24 +02:00
|
|
|
icon="magnify"
|
|
|
|
/>
|
|
|
|
</template>
|
2022-08-12 16:42:40 +02:00
|
|
|
<template #default="props">
|
2020-08-27 11:53:24 +02:00
|
|
|
{{ props.row.domain }}
|
|
|
|
</template>
|
2022-07-12 10:55:28 +02:00
|
|
|
</o-table-column>
|
|
|
|
<template #empty>
|
2021-05-12 18:10:07 +02:00
|
|
|
<empty-content icon="account-group" :inline="true">
|
2022-08-26 16:08:58 +02:00
|
|
|
{{ t("No group matches the filters") }}
|
2021-05-12 18:10:07 +02:00
|
|
|
</empty-content>
|
2020-08-27 11:53:24 +02:00
|
|
|
</template>
|
2022-07-12 10:55:28 +02:00
|
|
|
</o-table>
|
2020-08-27 11:53:24 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
2022-07-12 10:55:28 +02:00
|
|
|
<script lang="ts" setup>
|
2020-08-31 12:40:30 +02:00
|
|
|
import { LIST_GROUPS } from "@/graphql/group";
|
2020-08-27 11:53:24 +02:00
|
|
|
import RouteName from "../../router/name";
|
2021-05-12 18:10:07 +02:00
|
|
|
import EmptyContent from "../../components/Utils/EmptyContent.vue";
|
2022-07-12 10:55:28 +02:00
|
|
|
import { useRestrictions } from "@/composition/apollo/config";
|
|
|
|
import { useQuery } from "@vue/apollo-composable";
|
|
|
|
import {
|
|
|
|
booleanTransformer,
|
|
|
|
integerTransformer,
|
|
|
|
useRouteQuery,
|
|
|
|
} from "vue-use-route-query";
|
|
|
|
import { useI18n } from "vue-i18n";
|
|
|
|
import { useHead } from "@vueuse/head";
|
|
|
|
import { computed } from "vue";
|
|
|
|
import { Paginate } from "@/types/paginate";
|
|
|
|
import { IGroup } from "@/types/actor";
|
|
|
|
import AccountGroup from "vue-material-design-icons/AccountGroup.vue";
|
2020-08-27 11:53:24 +02:00
|
|
|
|
|
|
|
const PROFILES_PER_PAGE = 10;
|
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const { restrictions } = useRestrictions();
|
|
|
|
|
|
|
|
const preferredUsername = useRouteQuery("preferredUsername", "");
|
|
|
|
const name = useRouteQuery("name", "");
|
|
|
|
const domain = useRouteQuery("domain", "");
|
|
|
|
const local = useRouteQuery("local", false, booleanTransformer);
|
|
|
|
const suspended = useRouteQuery("suspended", false, booleanTransformer);
|
|
|
|
const page = useRouteQuery("page", 1, integerTransformer);
|
|
|
|
|
|
|
|
const {
|
|
|
|
result: groupsResult,
|
|
|
|
fetchMore,
|
|
|
|
loading,
|
|
|
|
} = useQuery<{
|
|
|
|
groups: Paginate<IGroup>;
|
|
|
|
}>(LIST_GROUPS, () => ({
|
|
|
|
preferredUsername: preferredUsername.value,
|
|
|
|
name: name.value,
|
|
|
|
domain: domain.value,
|
|
|
|
local: local.value,
|
|
|
|
suspended: suspended.value,
|
|
|
|
page: page.value,
|
|
|
|
limit: PROFILES_PER_PAGE,
|
|
|
|
}));
|
|
|
|
|
|
|
|
const groups = computed(() => groupsResult.value?.groups);
|
|
|
|
|
|
|
|
const { t } = useI18n({ useScope: "global" });
|
|
|
|
|
|
|
|
useHead({ title: computed(() => t("Groups")) });
|
|
|
|
|
|
|
|
const onPageChange = async (): Promise<void> => {
|
|
|
|
await doFetchMore();
|
|
|
|
};
|
|
|
|
|
|
|
|
const showCreateGroupsButton = computed((): boolean => {
|
|
|
|
return !!restrictions.value?.onlyAdminCanCreateGroups;
|
|
|
|
});
|
|
|
|
|
|
|
|
const onFiltersChange = ({
|
|
|
|
preferredUsername: newPreferredUsername,
|
|
|
|
domain: newDomain,
|
|
|
|
}: {
|
|
|
|
preferredUsername: string;
|
|
|
|
domain: string;
|
|
|
|
}): void => {
|
|
|
|
preferredUsername.value = newPreferredUsername;
|
|
|
|
domain.value = newDomain;
|
|
|
|
doFetchMore();
|
|
|
|
};
|
|
|
|
|
|
|
|
const doFetchMore = async (): Promise<void> => {
|
|
|
|
await fetchMore({
|
|
|
|
variables: {
|
|
|
|
preferredUsername: preferredUsername.value,
|
|
|
|
name: name.value,
|
|
|
|
domain: domain.value,
|
|
|
|
local: local.value,
|
|
|
|
suspended: suspended.value,
|
|
|
|
page: page.value,
|
|
|
|
limit: PROFILES_PER_PAGE,
|
2020-08-27 11:53:24 +02:00
|
|
|
},
|
2022-07-12 10:55:28 +02:00
|
|
|
});
|
|
|
|
};
|
2020-08-27 11:53:24 +02:00
|
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
a.profile {
|
|
|
|
text-decoration: none;
|
|
|
|
}
|
|
|
|
</style>
|