mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-12 23:35:58 +00:00
fix(webapp): fix group performance (#8656)
* seed more Yoga group members * implement groupMembers pagination * load limited amount of group members * force show all members in group member list * remove unused import * - added virtual scrolling to ProfileList * - fixed linter error * load all when clicking the button * seed 3000 users * cleanup * lint * hide search when not all members are visible * fix email factory * - increased profileListVisibleCount to 6 --------- Co-authored-by: Sebastian Stein <sebastian@codepassion.de>
This commit is contained in:
parent
6ae392b6e3
commit
a0e4b49833
@ -11,6 +11,9 @@ import slugify from 'slug'
|
|||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
|
|
||||||
import { generateInviteCode } from '@graphql/resolvers/inviteCodes'
|
import { generateInviteCode } from '@graphql/resolvers/inviteCodes'
|
||||||
|
import { isUniqueFor } from '@middleware/sluggifyMiddleware'
|
||||||
|
import uniqueSlug from '@middleware/slugify/uniqueSlug'
|
||||||
|
import { Context } from '@src/server'
|
||||||
|
|
||||||
import { getDriver, getNeode } from './neo4j'
|
import { getDriver, getNeode } from './neo4j'
|
||||||
|
|
||||||
@ -22,8 +25,9 @@ const uniqueImageUrl = (imageUrl) => {
|
|||||||
return newUrl.toString()
|
return newUrl.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const driver = getDriver()
|
||||||
|
|
||||||
export const cleanDatabase = async ({ withMigrations } = { withMigrations: false }) => {
|
export const cleanDatabase = async ({ withMigrations } = { withMigrations: false }) => {
|
||||||
const driver = getDriver()
|
|
||||||
const session = driver.session()
|
const session = driver.session()
|
||||||
|
|
||||||
const clean = `
|
const clean = `
|
||||||
@ -89,9 +93,7 @@ Factory.define('basicUser')
|
|||||||
showShoutsPublicly: false,
|
showShoutsPublicly: false,
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
})
|
})
|
||||||
.attr('slug', ['slug', 'name'], (slug, name) => {
|
.attr('slug', null)
|
||||||
return slug || slugify(name, { lower: true })
|
|
||||||
})
|
|
||||||
.attr('encryptedPassword', ['password'], (password) => {
|
.attr('encryptedPassword', ['password'], (password) => {
|
||||||
// eslint-disable-next-line n/no-sync
|
// eslint-disable-next-line n/no-sync
|
||||||
return hashSync(password, 10)
|
return hashSync(password, 10)
|
||||||
@ -121,13 +123,24 @@ Factory.define('userWithAboutEmpty')
|
|||||||
Factory.define('user')
|
Factory.define('user')
|
||||||
.extend('basicUser')
|
.extend('basicUser')
|
||||||
.option('about', faker.lorem.paragraph)
|
.option('about', faker.lorem.paragraph)
|
||||||
.option('email', faker.internet.exampleEmail)
|
.option('email', null)
|
||||||
.option('avatar', () =>
|
.option('avatar', () =>
|
||||||
Factory.build('image', {
|
Factory.build('image', {
|
||||||
url: faker.image.avatar(),
|
url: faker.image.avatar(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.after(async (buildObject, options) => {
|
.after(async (buildObject, options) => {
|
||||||
|
// Ensure unique slug
|
||||||
|
if (!buildObject.slug) {
|
||||||
|
buildObject.slug = await uniqueSlug(
|
||||||
|
buildObject.name,
|
||||||
|
isUniqueFor({ driver } as unknown as Context, 'User'),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// Ensure unique email
|
||||||
|
if (!options.email) {
|
||||||
|
options.email = `${buildObject.slug as string}@example.org`
|
||||||
|
}
|
||||||
const [user, email, avatar] = await Promise.all([
|
const [user, email, avatar] = await Promise.all([
|
||||||
neode.create('User', buildObject),
|
neode.create('User', buildObject),
|
||||||
neode.create('EmailAddress', { email: options.email }),
|
neode.create('EmailAddress', { email: options.email }),
|
||||||
|
|||||||
@ -1197,11 +1197,22 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const additionalUsers: any[] = []
|
const additionalUsers: any[] = []
|
||||||
for (let i = 0; i < 30; i++) {
|
for (let i = 0; i < 3000; i++) {
|
||||||
const user = await Factory.build('user')
|
const user = await Factory.build('user')
|
||||||
await jennyRostock.relateTo(user, 'following')
|
await jennyRostock.relateTo(user, 'following')
|
||||||
await user.relateTo(jennyRostock, 'following')
|
await user.relateTo(jennyRostock, 'following')
|
||||||
additionalUsers.push(user)
|
additionalUsers.push(user)
|
||||||
|
|
||||||
|
const userObj = await user.toJson()
|
||||||
|
authenticatedUser = userObj
|
||||||
|
|
||||||
|
await mutate({
|
||||||
|
mutation: joinGroupMutation(),
|
||||||
|
variables: {
|
||||||
|
groupId: 'g2',
|
||||||
|
userId: userObj.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jenny users
|
// Jenny users
|
||||||
|
|||||||
@ -80,15 +80,18 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
GroupMembers: async (_object, params, context: Context, _resolveInfo) => {
|
GroupMembers: async (_object, params, context: Context, _resolveInfo) => {
|
||||||
const { id: groupId } = params
|
const { id: groupId, first = 25, offset = 0 } = params
|
||||||
const session = context.driver.session()
|
const session = context.driver.session()
|
||||||
const readTxResultPromise = session.readTransaction(async (txc) => {
|
const readTxResultPromise = session.readTransaction(async (txc) => {
|
||||||
const groupMemberCypher = `
|
const groupMemberCypher = `
|
||||||
MATCH (user:User)-[membership:MEMBER_OF]->(:Group {id: $groupId})
|
MATCH (user:User)-[membership:MEMBER_OF]->(:Group {id: $groupId})
|
||||||
RETURN user {.*, myRoleInGroup: membership.role}
|
RETURN user {.*, myRoleInGroup: membership.role}
|
||||||
|
SKIP toInteger($offset) LIMIT toInteger($first)
|
||||||
`
|
`
|
||||||
const transactionResponse = await txc.run(groupMemberCypher, {
|
const transactionResponse = await txc.run(groupMemberCypher, {
|
||||||
groupId,
|
groupId,
|
||||||
|
first,
|
||||||
|
offset,
|
||||||
})
|
})
|
||||||
return transactionResponse.records.map((record) => record.get('user'))
|
return transactionResponse.records.map((record) => record.get('user'))
|
||||||
})
|
})
|
||||||
@ -468,6 +471,9 @@ export default {
|
|||||||
isMutedByMe:
|
isMutedByMe:
|
||||||
'MATCH (this) RETURN EXISTS( (this)<-[:MUTED]-(:User {id: $cypherParams.currentUserId}) )',
|
'MATCH (this) RETURN EXISTS( (this)<-[:MUTED]-(:User {id: $cypherParams.currentUserId}) )',
|
||||||
},
|
},
|
||||||
|
count: {
|
||||||
|
membersCount: '<-[:MEMBER_OF]-(related:User)',
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
name: async (parent, _args, context: Context, _resolveInfo) => {
|
name: async (parent, _args, context: Context, _resolveInfo) => {
|
||||||
if (!context.user) {
|
if (!context.user) {
|
||||||
|
|||||||
@ -38,6 +38,8 @@ type Group {
|
|||||||
|
|
||||||
categories: [Category] @relation(name: "CATEGORIZED", direction: "OUT")
|
categories: [Category] @relation(name: "CATEGORIZED", direction: "OUT")
|
||||||
|
|
||||||
|
membersCount: Int! @cypher(statement: "MATCH (this)<-[:MEMBER_OF]-(r:User) RETURN COUNT(DISTINCT r)")
|
||||||
|
|
||||||
myRole: GroupMemberRole # if 'null' then the current user is no member
|
myRole: GroupMemberRole # if 'null' then the current user is no member
|
||||||
|
|
||||||
posts: [Post] @relation(name: "IN", direction: "IN")
|
posts: [Post] @relation(name: "IN", direction: "IN")
|
||||||
@ -78,8 +80,8 @@ type Query {
|
|||||||
|
|
||||||
GroupMembers(
|
GroupMembers(
|
||||||
id: ID!
|
id: ID!
|
||||||
# first: Int # not implemented yet
|
first: Int
|
||||||
# offset: Int # not implemented yet
|
offset: Int
|
||||||
# orderBy: [_UserOrdering] # not implemented yet
|
# orderBy: [_UserOrdering] # not implemented yet
|
||||||
# filter: _UserFilter # not implemented yet
|
# filter: _UserFilter # not implemented yet
|
||||||
): [User]
|
): [User]
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import type { Context } from '@src/server'
|
|||||||
|
|
||||||
import uniqueSlug from './slugify/uniqueSlug'
|
import uniqueSlug from './slugify/uniqueSlug'
|
||||||
|
|
||||||
const isUniqueFor = (context: Context, type: string) => {
|
export const isUniqueFor = (context: Context, type: string) => {
|
||||||
return async (slug: string) => {
|
return async (slug: string) => {
|
||||||
const session = context.driver.session()
|
const session = context.driver.session()
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -4,24 +4,44 @@
|
|||||||
<h5 class="title spacer-x-small">
|
<h5 class="title spacer-x-small">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h5>
|
</h5>
|
||||||
<ul :class="profilesClass">
|
|
||||||
|
<!-- Virtual Scroller for better performance -->
|
||||||
|
<recycle-scroller
|
||||||
|
v-if="isMoreAsVisible && showVirtualScroll"
|
||||||
|
:items="filteredConnections"
|
||||||
|
:item-size="itemHeight"
|
||||||
|
key-field="id"
|
||||||
|
:class="profilesClass"
|
||||||
|
class="profiles-virtual"
|
||||||
|
v-slot="{ item }"
|
||||||
|
>
|
||||||
|
<div class="connections__item">
|
||||||
|
<user-teaser :user="item" />
|
||||||
|
</div>
|
||||||
|
</recycle-scroller>
|
||||||
|
|
||||||
|
<!-- Normal list for only a few items -->
|
||||||
|
<ul v-else :class="profilesClass">
|
||||||
<li
|
<li
|
||||||
v-for="connection in filteredConnections"
|
v-for="connection in displayedConnections"
|
||||||
:key="connection.id"
|
:key="connection.id"
|
||||||
class="connections__item"
|
class="connections__item"
|
||||||
>
|
>
|
||||||
<user-teaser :user="connection" />
|
<user-teaser :user="connection" />
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ds-input
|
<ds-input
|
||||||
v-if="isMoreAsVisible"
|
v-if="isMoreAsVisible && !hasMore"
|
||||||
:name="uniqueName"
|
:name="uniqueName"
|
||||||
:placeholder="filter"
|
:placeholder="filterPlaceholder"
|
||||||
|
:value="filter"
|
||||||
class="spacer-x-small"
|
class="spacer-x-small"
|
||||||
icon="filter"
|
icon="filter"
|
||||||
size="small"
|
size="small"
|
||||||
@input.native="setFilter"
|
@input.native="setFilter"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<base-button
|
<base-button
|
||||||
v-if="hasMore"
|
v-if="hasMore"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
@ -42,14 +62,19 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { escape } from 'xregexp/xregexp-all.js'
|
import { escape } from 'xregexp/xregexp-all.js'
|
||||||
|
// @ts-ignore
|
||||||
|
import { RecycleScroller } from 'vue-virtual-scroller'
|
||||||
|
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
||||||
import UserTeaser from '~/components/UserTeaser/UserTeaser'
|
import UserTeaser from '~/components/UserTeaser/UserTeaser'
|
||||||
|
|
||||||
export const profileListVisibleCount = 7
|
export const profileListVisibleCount = 6
|
||||||
|
const VIRTUAL_SCROLL_THRESHOLD = 50
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ProfileList',
|
name: 'ProfileList',
|
||||||
components: {
|
components: {
|
||||||
UserTeaser,
|
UserTeaser,
|
||||||
|
RecycleScroller,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
uniqueName: { type: String, required: true },
|
uniqueName: { type: String, required: true },
|
||||||
@ -63,6 +88,8 @@ export default {
|
|||||||
return {
|
return {
|
||||||
profileListVisibleCount,
|
profileListVisibleCount,
|
||||||
filter: null,
|
filter: null,
|
||||||
|
itemHeight: 56,
|
||||||
|
filterPlaceholder: this.$t('common.filter', 'Filter...'),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -72,17 +99,34 @@ export default {
|
|||||||
isMoreAsVisible() {
|
isMoreAsVisible() {
|
||||||
return this.profiles.length > this.profileListVisibleCount
|
return this.profiles.length > this.profileListVisibleCount
|
||||||
},
|
},
|
||||||
|
showVirtualScroll() {
|
||||||
|
return process.client && this.filteredConnections.length > VIRTUAL_SCROLL_THRESHOLD
|
||||||
|
},
|
||||||
profilesClass() {
|
profilesClass() {
|
||||||
return `profiles${this.isMoreAsVisible ? ' --overflow' : ''}`
|
return `profiles${this.isMoreAsVisible ? ' --overflow' : ''}`
|
||||||
},
|
},
|
||||||
|
displayedConnections() {
|
||||||
|
return this.isMoreAsVisible
|
||||||
|
? this.filteredConnections
|
||||||
|
: this.filteredConnections.slice(0, this.profileListVisibleCount)
|
||||||
|
},
|
||||||
filteredConnections() {
|
filteredConnections() {
|
||||||
if (!this.filter) {
|
if (!this.filter) {
|
||||||
return this.profiles
|
return this.profiles
|
||||||
}
|
}
|
||||||
|
|
||||||
// @example
|
const filterLower = this.filter.toLowerCase()
|
||||||
// this.filter = 'foo';
|
|
||||||
// fuzzyExpression = /([^f]*f)([^o]*o)([^o]*o)/i
|
const simpleMatches = this.profiles.filter((user) => {
|
||||||
|
const name = (user.name || '').toLowerCase()
|
||||||
|
const slug = (user.slug || '').toLowerCase()
|
||||||
|
return name.includes(filterLower) || slug.includes(filterLower)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (simpleMatches.length > 0) {
|
||||||
|
return simpleMatches
|
||||||
|
}
|
||||||
|
|
||||||
const fuzzyExpression = new RegExp(
|
const fuzzyExpression = new RegExp(
|
||||||
`${this.filter.split('').reduce((expr, c) => `${expr}([^${escape(c)}]*${escape(c)})`, '')}`,
|
`${this.filter.split('').reduce((expr, c) => `${expr}([^${escape(c)}]*${escape(c)})`, '')}`,
|
||||||
'i',
|
'i',
|
||||||
@ -151,6 +195,26 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.profiles-virtual {
|
||||||
|
height: $size-height-connections;
|
||||||
|
padding: $space-none;
|
||||||
|
|
||||||
|
&.--overflow {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connections__item {
|
||||||
|
padding: $space-xx-small;
|
||||||
|
height: 56px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $background-color-primary-inverse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.nobody-message {
|
.nobody-message {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: $text-color-soft;
|
color: $text-color-soft;
|
||||||
@ -160,4 +224,8 @@ export default {
|
|||||||
margin-bottom: $space-small;
|
margin-bottom: $space-small;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vue-recycle-scroller__item-wrapper {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -194,6 +194,7 @@ export const groupQuery = (i18n) => {
|
|||||||
lng
|
lng
|
||||||
lat
|
lat
|
||||||
}
|
}
|
||||||
|
membersCount
|
||||||
myRole
|
myRole
|
||||||
inviteCodes {
|
inviteCodes {
|
||||||
createdAt
|
createdAt
|
||||||
@ -212,8 +213,8 @@ export const groupQuery = (i18n) => {
|
|||||||
|
|
||||||
export const groupMembersQuery = () => {
|
export const groupMembersQuery = () => {
|
||||||
return gql`
|
return gql`
|
||||||
query ($id: ID!) {
|
query ($id: ID!, $first: Int, $offset: Int) {
|
||||||
GroupMembers(id: $id) {
|
GroupMembers(id: $id, first: $first, offset: $offset) {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
slug
|
slug
|
||||||
|
|||||||
@ -61,6 +61,7 @@
|
|||||||
"vue-observe-visibility": "^1.0.0",
|
"vue-observe-visibility": "^1.0.0",
|
||||||
"vue-scrollto": "^2.20.0",
|
"vue-scrollto": "^2.20.0",
|
||||||
"vue-sweetalert-icons": "~4.3.1",
|
"vue-sweetalert-icons": "~4.3.1",
|
||||||
|
"vue-virtual-scroller": "^1.1.2",
|
||||||
"vue2-datepicker": "^3.11.1",
|
"vue2-datepicker": "^3.11.1",
|
||||||
"vuex-i18n": "~1.13.1",
|
"vuex-i18n": "~1.13.1",
|
||||||
"xregexp": "^5.1.2",
|
"xregexp": "^5.1.2",
|
||||||
|
|||||||
@ -55,29 +55,11 @@
|
|||||||
<count-to
|
<count-to
|
||||||
slot="count"
|
slot="count"
|
||||||
:start-val="membersCountStartValue"
|
:start-val="membersCountStartValue"
|
||||||
:end-val="groupMembers.length"
|
:end-val="group.membersCount"
|
||||||
/>
|
/>
|
||||||
</ds-number>
|
</ds-number>
|
||||||
</client-only>
|
</client-only>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<!-- <ds-flex-item>
|
|
||||||
<client-only>
|
|
||||||
<ds-number :label="$t('profile.followers')">
|
|
||||||
<count-to
|
|
||||||
slot="count"
|
|
||||||
:start-val="followedByCountStartValue"
|
|
||||||
:end-val="user.followedByCount"
|
|
||||||
/>
|
|
||||||
</ds-number>
|
|
||||||
</client-only>
|
|
||||||
</ds-flex-item> -->
|
|
||||||
<!-- <ds-flex-item>
|
|
||||||
<client-only>
|
|
||||||
<ds-number :label="$t('profile.following')">
|
|
||||||
<count-to slot="count" :end-val="user.followingCount" />
|
|
||||||
</ds-number>
|
|
||||||
</client-only>
|
|
||||||
</ds-flex-item> -->
|
|
||||||
</ds-flex>
|
</ds-flex>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<base-button danger v-if="group.isMutedByMe" @click="unmuteGroup" icon="volume-up">
|
<base-button danger v-if="group.isMutedByMe" @click="unmuteGroup" icon="volume-up">
|
||||||
@ -194,25 +176,11 @@
|
|||||||
? $t('group.membersListTitleNotAllowedSeeingGroupMembers')
|
? $t('group.membersListTitleNotAllowedSeeingGroupMembers')
|
||||||
: null
|
: null
|
||||||
"
|
"
|
||||||
:allProfilesCount="isAllowedSeeingGroupMembers ? groupMembers.length : 0"
|
:allProfilesCount="isAllowedSeeingGroupMembers ? group.membersCount : 0"
|
||||||
:profiles="isAllowedSeeingGroupMembers ? groupMembers : []"
|
:profiles="isAllowedSeeingGroupMembers ? groupMembers : []"
|
||||||
:loading="$apollo.loading"
|
:loading="$apollo.loading"
|
||||||
@fetchAllProfiles="fetchAllMembers"
|
@fetchAllProfiles="fetchAllMembers"
|
||||||
/>
|
/>
|
||||||
<!-- <ds-space />
|
|
||||||
<follow-list
|
|
||||||
:loading="$apollo.loading"
|
|
||||||
:user="user"
|
|
||||||
type="followedBy"
|
|
||||||
@fetchAllConnections="fetchAllConnections"
|
|
||||||
/>
|
|
||||||
<ds-space />
|
|
||||||
<follow-list
|
|
||||||
:loading="$apollo.loading"
|
|
||||||
:user="user"
|
|
||||||
type="following"
|
|
||||||
@fetchAllConnections="fetchAllConnections"
|
|
||||||
/> -->
|
|
||||||
<!-- <social-media :user-name="groupName" :user="user" /> -->
|
<!-- <social-media :user-name="groupName" :user="user" /> -->
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
|
|
||||||
@ -310,8 +278,6 @@ import Category from '~/components/Category'
|
|||||||
import ContentViewer from '~/components/Editor/ContentViewer'
|
import ContentViewer from '~/components/Editor/ContentViewer'
|
||||||
import CountTo from '~/components/CountTo.vue'
|
import CountTo from '~/components/CountTo.vue'
|
||||||
import Empty from '~/components/Empty/Empty'
|
import Empty from '~/components/Empty/Empty'
|
||||||
// import FollowButton from '~/components/Button/FollowButton'
|
|
||||||
// import FollowList from '~/components/features/ProfileList/FollowList'
|
|
||||||
import GroupContentMenu from '~/components/ContentMenu/GroupContentMenu'
|
import GroupContentMenu from '~/components/ContentMenu/GroupContentMenu'
|
||||||
import JoinLeaveButton from '~/components/Button/JoinLeaveButton'
|
import JoinLeaveButton from '~/components/Button/JoinLeaveButton'
|
||||||
import MasonryGrid from '~/components/MasonryGrid/MasonryGrid.vue'
|
import MasonryGrid from '~/components/MasonryGrid/MasonryGrid.vue'
|
||||||
@ -340,8 +306,6 @@ export default {
|
|||||||
ContentViewer,
|
ContentViewer,
|
||||||
CountTo,
|
CountTo,
|
||||||
Empty,
|
Empty,
|
||||||
// FollowButton,
|
|
||||||
// FollowList,
|
|
||||||
GroupContentMenu,
|
GroupContentMenu,
|
||||||
JoinLeaveButton,
|
JoinLeaveButton,
|
||||||
PostTeaser,
|
PostTeaser,
|
||||||
@ -373,11 +337,8 @@ export default {
|
|||||||
pageSize: 6,
|
pageSize: 6,
|
||||||
// tabActive: 'post',
|
// tabActive: 'post',
|
||||||
filter,
|
filter,
|
||||||
// followedByCountStartValue: 0,
|
|
||||||
// followedByCount: 7,
|
|
||||||
// followingCount: 7,
|
|
||||||
membersCountStartValue: 0,
|
membersCountStartValue: 0,
|
||||||
membersCountToLoad: Infinity,
|
membersCountToLoad: 25,
|
||||||
updateGroupMutation,
|
updateGroupMutation,
|
||||||
isDescriptionCollapsed: true,
|
isDescriptionCollapsed: true,
|
||||||
}
|
}
|
||||||
@ -593,7 +554,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetchAllMembers() {
|
fetchAllMembers() {
|
||||||
this.membersCountToLoad = Infinity
|
this.membersCountToLoad = this.group.membersCount
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
apollo: {
|
apollo: {
|
||||||
@ -621,8 +582,6 @@ export default {
|
|||||||
variables() {
|
variables() {
|
||||||
return {
|
return {
|
||||||
id: this.$route.params.id,
|
id: this.$route.params.id,
|
||||||
// followedByCount: this.followedByCount,
|
|
||||||
// followingCount: this.followingCount,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error(error) {
|
error(error) {
|
||||||
@ -637,6 +596,7 @@ export default {
|
|||||||
variables() {
|
variables() {
|
||||||
return {
|
return {
|
||||||
id: this.$route.params.id,
|
id: this.$route.params.id,
|
||||||
|
first: this.membersCountToLoad,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
skip() {
|
skip() {
|
||||||
|
|||||||
@ -45,6 +45,7 @@ export default {
|
|||||||
variables() {
|
variables() {
|
||||||
return {
|
return {
|
||||||
id: this.group.id,
|
id: this.group.id,
|
||||||
|
first: 999999,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error(error) {
|
error(error) {
|
||||||
|
|||||||
@ -17417,6 +17417,11 @@ schema-utils@^3.0.0:
|
|||||||
ajv "^6.12.5"
|
ajv "^6.12.5"
|
||||||
ajv-keywords "^3.5.2"
|
ajv-keywords "^3.5.2"
|
||||||
|
|
||||||
|
scrollparent@^2.0.1:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/scrollparent/-/scrollparent-2.1.0.tgz#6cae915c953835886a6ba0d77fdc2bb1ed09076d"
|
||||||
|
integrity sha512-bnnvJL28/Rtz/kz2+4wpBjHzWoEzXhVg/TE8BeVGJHUqE8THNIRnDxDWMktwM+qahvlRdvlLdsQfYe+cuqfZeA==
|
||||||
|
|
||||||
select@^1.1.2:
|
select@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
|
resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
|
||||||
@ -19825,11 +19830,21 @@ vue-no-ssr@^1.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/vue-no-ssr/-/vue-no-ssr-1.1.1.tgz#875f3be6fb0ae41568a837f3ac1a80eaa137b998"
|
resolved "https://registry.yarnpkg.com/vue-no-ssr/-/vue-no-ssr-1.1.1.tgz#875f3be6fb0ae41568a837f3ac1a80eaa137b998"
|
||||||
integrity sha512-ZMjqRpWabMPqPc7gIrG0Nw6vRf1+itwf0Itft7LbMXs2g3Zs/NFmevjZGN1x7K3Q95GmIjWbQZTVerxiBxI+0g==
|
integrity sha512-ZMjqRpWabMPqPc7gIrG0Nw6vRf1+itwf0Itft7LbMXs2g3Zs/NFmevjZGN1x7K3Q95GmIjWbQZTVerxiBxI+0g==
|
||||||
|
|
||||||
|
vue-observe-visibility@^0.4.4:
|
||||||
|
version "0.4.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-observe-visibility/-/vue-observe-visibility-0.4.6.tgz#878cb8ebcf3078e40807af29774e97105ebd519e"
|
||||||
|
integrity sha512-xo0CEVdkjSjhJoDdLSvoZoQrw/H2BlzB5jrCBKGZNXN2zdZgMuZ9BKrxXDjNP2AxlcCoKc8OahI3F3r3JGLv2Q==
|
||||||
|
|
||||||
vue-observe-visibility@^1.0.0:
|
vue-observe-visibility@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/vue-observe-visibility/-/vue-observe-visibility-1.0.0.tgz#17cf1b2caf74022f0f3c95371468ddf2b9573152"
|
resolved "https://registry.yarnpkg.com/vue-observe-visibility/-/vue-observe-visibility-1.0.0.tgz#17cf1b2caf74022f0f3c95371468ddf2b9573152"
|
||||||
integrity sha512-s5TFh3s3h3Mhd3jaz3zGzkVHKHnc/0C/gNr30olO99+yw2hl3WBhK3ng3/f9OF+qkW4+l7GkmwfAzDAcY3lCFg==
|
integrity sha512-s5TFh3s3h3Mhd3jaz3zGzkVHKHnc/0C/gNr30olO99+yw2hl3WBhK3ng3/f9OF+qkW4+l7GkmwfAzDAcY3lCFg==
|
||||||
|
|
||||||
|
vue-resize@^0.4.5:
|
||||||
|
version "0.4.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-0.4.5.tgz#4777a23042e3c05620d9cbda01c0b3cc5e32dcea"
|
||||||
|
integrity sha512-bhP7MlgJQ8TIkZJXAfDf78uJO+mEI3CaLABLjv0WNzr4CcGRGPIAItyWYnP6LsPA4Oq0WE+suidNs6dgpO4RHg==
|
||||||
|
|
||||||
vue-resize@^1.0.1:
|
vue-resize@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-1.0.1.tgz#c120bed4e09938771d622614f57dbcf58a5147ee"
|
resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-1.0.1.tgz#c120bed4e09938771d622614f57dbcf58a5147ee"
|
||||||
@ -19900,6 +19915,15 @@ vue-template-es2015-compiler@^1.9.0:
|
|||||||
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
||||||
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
||||||
|
|
||||||
|
vue-virtual-scroller@^1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-virtual-scroller/-/vue-virtual-scroller-1.1.2.tgz#b8a6362f177abf3f2149ce1eac18013c71fe353b"
|
||||||
|
integrity sha512-SkUyc7QHCJFB5h1Fya7LxVizlVzOZZuFVipBGHYoTK8dwLs08bIz/tclvRApYhksaJIm/nn51inzO2UjpGJPMQ==
|
||||||
|
dependencies:
|
||||||
|
scrollparent "^2.0.1"
|
||||||
|
vue-observe-visibility "^0.4.4"
|
||||||
|
vue-resize "^0.4.5"
|
||||||
|
|
||||||
vue2-datepicker@^3.11.1:
|
vue2-datepicker@^3.11.1:
|
||||||
version "3.11.1"
|
version "3.11.1"
|
||||||
resolved "https://registry.yarnpkg.com/vue2-datepicker/-/vue2-datepicker-3.11.1.tgz#b2124e15f694d0fd43a92558f6929ec29338d241"
|
resolved "https://registry.yarnpkg.com/vue2-datepicker/-/vue2-datepicker-3.11.1.tgz#b2124e15f694d0fd43a92558f6929ec29338d241"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user