mirror of
https://github.com/nextcloud/contacts.git
synced 2025-07-20 16:54:44 +00:00
refactor: Circle details
There is no list view for circles so we do not need AppContentDetails / AppContentList. Make the member list reactive and separate into smaller chunks Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
@ -4,41 +4,20 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<AppContent v-if="!circle">
|
||||
<EmptyContent :name="t('contacts', 'Please select a team')">
|
||||
<AppContent>
|
||||
<EmptyContent v-if="!circle" :name="t('contacts', 'Please select a team')">
|
||||
<template #icon>
|
||||
<AccountGroup :size="20" />
|
||||
</template>
|
||||
</EmptyContent>
|
||||
</AppContent>
|
||||
|
||||
<AppContent v-else-if="loading">
|
||||
<EmptyContent class="empty-content" :name="t('contacts', 'Loading team…')">
|
||||
<EmptyContent v-else-if="loading" class="empty-content" :name="t('contacts', 'Loading team…')">
|
||||
<template #icon>
|
||||
<IconLoading :size="20" />
|
||||
</template>
|
||||
</EmptyContent>
|
||||
</AppContent>
|
||||
|
||||
<AppContent v-else :show-details.sync="showDetails">
|
||||
<!-- main contacts details -->
|
||||
<CircleDetails :circle="circle">
|
||||
<!-- not a member -->
|
||||
<template v-if="!circle.isMember">
|
||||
<!-- Pending request validation -->
|
||||
<EmptyContent v-if="circle.isPendingMember" :name="t('contacts', 'Your request to join this team is pending approval')">
|
||||
<template #icon>
|
||||
<IconLoading :size="20" />
|
||||
</template>
|
||||
</EmptyContent>
|
||||
|
||||
<EmptyContent v-else :name="t('contacts', 'You are not a member of {circle}', { circle: circle.displayName})">
|
||||
<template #icon>
|
||||
<AccountGroup :size="20" />
|
||||
</template>
|
||||
</EmptyContent>
|
||||
</template>
|
||||
</CircleDetails>
|
||||
<CircleDetails v-else :circle="circle" />
|
||||
</AppContent>
|
||||
</template>
|
||||
<script>
|
||||
@ -76,7 +55,6 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
loadingList: false,
|
||||
showDetails: false,
|
||||
}
|
||||
},
|
||||
|
||||
@ -130,11 +108,6 @@ export default {
|
||||
this.loadingList = false
|
||||
}
|
||||
},
|
||||
|
||||
// Hide the circle details
|
||||
hideDetails() {
|
||||
this.showDetails = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -4,7 +4,7 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<AppContentDetails>
|
||||
<div class="circle-details">
|
||||
<!-- contact header -->
|
||||
<DetailsHeader>
|
||||
<!-- avatar and upload photo -->
|
||||
@ -72,7 +72,25 @@
|
||||
@update:value="onDescriptionChangeDebounce" />
|
||||
</section>
|
||||
|
||||
<section v-if="circle.isMember">
|
||||
<!-- not a member -->
|
||||
<template v-if="!circle.isMember">
|
||||
<!-- Pending request validation -->
|
||||
<NcEmptyContent v-if="circle.isPendingMember"
|
||||
:name="t('contacts', 'Your request to join this team is pending approval')">
|
||||
<template #icon>
|
||||
<NcLoadingIcon :size="20" />
|
||||
</template>
|
||||
</NcEmptyContent>
|
||||
|
||||
<NcEmptyContent v-else
|
||||
:name="t('contacts', 'You are not a member of {circle}', { circle: circle.displayName})">
|
||||
<template #icon>
|
||||
<IconAccountGroup :size="20" />
|
||||
</template>
|
||||
</NcEmptyContent>
|
||||
</template>
|
||||
|
||||
<section v-else>
|
||||
<ContentHeading>
|
||||
{{ t('contacts', 'Team resources') }}
|
||||
</ContentHeading>
|
||||
@ -102,12 +120,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-if="members.length > 0">
|
||||
<ContentHeading>
|
||||
{{ t('contacts', 'Team members') }}
|
||||
</ContentHeading>
|
||||
<MemberList :list="members" />
|
||||
</section>
|
||||
<MemberList v-if="members.length" :list="members" />
|
||||
|
||||
<Modal v-if="(circle.isOwner || circle.isAdmin) && !circle.isPersonal && showSettingsModal" @close="showSettingsModal=false">
|
||||
<div class="circle-settings">
|
||||
@ -161,11 +174,7 @@
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<section v-else>
|
||||
<slot />
|
||||
</section>
|
||||
</AppContentDetails>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -177,10 +186,11 @@ import { showError } from '@nextcloud/dialogs'
|
||||
import axios from '@nextcloud/axios'
|
||||
|
||||
import {
|
||||
NcAppContentDetails as AppContentDetails,
|
||||
NcAvatar as Avatar,
|
||||
NcButton as Button,
|
||||
NcEmptyContent,
|
||||
NcListItem as ListItem,
|
||||
NcLoadingIcon,
|
||||
NcModal as Modal,
|
||||
NcRichContenteditable as RichContenteditable,
|
||||
} from '@nextcloud/vue'
|
||||
@ -189,12 +199,13 @@ import Cog from 'vue-material-design-icons/Cog.vue'
|
||||
import Login from 'vue-material-design-icons/Login.vue'
|
||||
import Logout from 'vue-material-design-icons/Logout.vue'
|
||||
import IconDelete from 'vue-material-design-icons/Delete.vue'
|
||||
import IconAccountGroup from 'vue-material-design-icons/AccountGroup.vue'
|
||||
|
||||
import { CircleEdit, editCircle } from '../services/circles.ts'
|
||||
import CircleActionsMixin from '../mixins/CircleActionsMixin.js'
|
||||
import DetailsHeader from './DetailsHeader.vue'
|
||||
import CircleConfigs from './CircleDetails/CircleConfigs.vue'
|
||||
import MemberList from './MemberList.vue'
|
||||
import MemberList from './MemberList/MemberList.vue'
|
||||
import ContentHeading from './CircleDetails/ContentHeading.vue'
|
||||
import CirclePasswordSettings from './CircleDetails/CirclePasswordSettings.vue'
|
||||
|
||||
@ -202,9 +213,7 @@ export default {
|
||||
name: 'CircleDetails',
|
||||
|
||||
components: {
|
||||
AppContentDetails,
|
||||
Avatar,
|
||||
MemberList,
|
||||
Button,
|
||||
CircleConfigs,
|
||||
CirclePasswordSettings,
|
||||
@ -212,10 +221,14 @@ export default {
|
||||
DetailsHeader,
|
||||
ListItem,
|
||||
Cog,
|
||||
IconAccountGroup,
|
||||
IconDelete,
|
||||
Login,
|
||||
Logout,
|
||||
MemberList,
|
||||
Modal,
|
||||
IconDelete,
|
||||
NcEmptyContent,
|
||||
NcLoadingIcon,
|
||||
RichContenteditable,
|
||||
},
|
||||
|
||||
@ -384,6 +397,10 @@ export default {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.circle-details {
|
||||
padding-inline: 20px;
|
||||
}
|
||||
|
||||
.circle-details-section {
|
||||
&:not(:first-of-type) {
|
||||
margin-top: 24px;
|
||||
|
@ -75,6 +75,7 @@ $top-padding: 50px;
|
||||
.contact-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
padding: $top-padding 0 20px;
|
||||
gap: $contact-details-row-gap;
|
||||
&__quick-actions{
|
||||
|
@ -4,46 +4,50 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<AppContentList v-if="!hasMembers" class="members-list">
|
||||
<template v-if="loading">
|
||||
<EmptyContent class="empty-content" :name="t('contacts', 'Loading members list …')">
|
||||
<template #icon>
|
||||
<IconLoading :size="20" />
|
||||
</template>
|
||||
</EmptyContent>
|
||||
</template>
|
||||
<template v-else-if="!circle.isMember">
|
||||
<EmptyContent class="empty-content" :name="t('contacts', 'The list of members is only visible to members of this team')">
|
||||
<template #icon>
|
||||
<IconContact :size="20" />
|
||||
</template>
|
||||
</EmptyContent>
|
||||
</template>
|
||||
<template v-else>
|
||||
<EmptyContent class="empty-content" :name="t('contacts', 'You currently have no access to the member list')">
|
||||
<template #icon>
|
||||
<IconContact :size="20" />
|
||||
</template>
|
||||
</EmptyContent>
|
||||
</template>
|
||||
</AppContentList>
|
||||
<section class="member-list">
|
||||
<ContentHeading>
|
||||
{{ t('contacts', 'Team members') }}
|
||||
</ContentHeading>
|
||||
|
||||
<AppContentList v-else>
|
||||
<div class="members-list__new">
|
||||
<Button v-if="circle.canManageMembers"
|
||||
@click="onShowPicker(circle.id)">
|
||||
<template #icon>
|
||||
<IconLoading v-if="loading" />
|
||||
<IconAdd :size="20" />
|
||||
</template>
|
||||
{{ t('contacts', 'Add members') }}
|
||||
</Button>
|
||||
<NcEmptyContent v-if="loading" class="empty-content" :name="t('contacts', 'Loading members list …')">
|
||||
<template #icon>
|
||||
<IconLoading :size="20" />
|
||||
</template>
|
||||
</NcEmptyContent>
|
||||
|
||||
<NcEmptyContent v-else-if="!circle.isMember"
|
||||
class="empty-content"
|
||||
:name="t('contacts', 'The list of members is only visible to members of this team')">
|
||||
<template #icon>
|
||||
<IconContact :size="20" />
|
||||
</template>
|
||||
</NcEmptyContent>
|
||||
|
||||
<NcEmptyContent v-else-if="!hasMembers"
|
||||
class="empty-content"
|
||||
:name="t('contacts', 'You currently have no access to the member list')">
|
||||
<template #icon>
|
||||
<IconContact :size="20" />
|
||||
</template>
|
||||
</NcEmptyContent>
|
||||
|
||||
<div v-else>
|
||||
<div class="member-list__new">
|
||||
<NcButton v-if="circle.canManageMembers"
|
||||
@click="onShowPicker(circle.id)">
|
||||
<template #icon>
|
||||
<NcLoadingIcon v-if="loading" />
|
||||
<IconAdd v-else :size="20" />
|
||||
</template>
|
||||
{{ t('contacts', 'Add members') }}
|
||||
</NcButton>
|
||||
</div>
|
||||
|
||||
<MemberListGroup v-for="group, index in groupedList"
|
||||
:key="`member-list-group-${index}`"
|
||||
v-bind="group" />
|
||||
</div>
|
||||
|
||||
<MembersListItem v-for="member in filteredList"
|
||||
:key="member.singleId"
|
||||
:source="member" />
|
||||
|
||||
<!-- member picker -->
|
||||
<EntityPicker v-if="showPicker"
|
||||
:confirm-label="t('contacts', 'Add to {circle}', { circle: circle.displayName })"
|
||||
@ -55,42 +59,43 @@
|
||||
@close="resetPicker"
|
||||
@search="onSearch"
|
||||
@submit="onPickerPick" />
|
||||
</AppContentList>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {
|
||||
NcAppContentList as AppContentList,
|
||||
NcButton as Button,
|
||||
NcEmptyContent as EmptyContent,
|
||||
NcLoadingIcon as IconLoading,
|
||||
NcButton,
|
||||
NcEmptyContent,
|
||||
NcLoadingIcon,
|
||||
isMobile,
|
||||
} from '@nextcloud/vue'
|
||||
|
||||
import MembersListItem from './MembersList/MembersListItem.vue'
|
||||
import EntityPicker from './EntityPicker/EntityPicker.vue'
|
||||
import MemberListGroup from './MemberListGroup.vue'
|
||||
import EntityPicker from '../EntityPicker/EntityPicker.vue'
|
||||
import IconContact from 'vue-material-design-icons/AccountMultiple.vue'
|
||||
import IconAdd from 'vue-material-design-icons/Plus.vue'
|
||||
import RouterMixin from '../mixins/RouterMixin.js'
|
||||
import RouterMixin from '../../mixins/RouterMixin.js'
|
||||
|
||||
import { getRecommendations, getSuggestions } from '../services/collaborationAutocompletion.js'
|
||||
import { showError, showWarning } from '@nextcloud/dialogs'
|
||||
import { subscribe } from '@nextcloud/event-bus'
|
||||
import { SHARES_TYPES_MEMBER_MAP, CIRCLES_MEMBER_GROUPING } from '../models/constants.ts'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { getRecommendations, getSuggestions } from '../../services/collaborationAutocompletion.js'
|
||||
import { SHARES_TYPES_MEMBER_MAP, CIRCLES_MEMBER_GROUPING } from '../../models/constants'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'MemberList',
|
||||
|
||||
components: {
|
||||
AppContentList,
|
||||
Button,
|
||||
EntityPicker,
|
||||
EmptyContent,
|
||||
IconContact,
|
||||
IconAdd,
|
||||
IconLoading,
|
||||
MembersListItem,
|
||||
MemberListGroup,
|
||||
NcButton,
|
||||
NcEmptyContent,
|
||||
NcLoadingIcon,
|
||||
},
|
||||
|
||||
mixins: [isMobile, RouterMixin],
|
||||
|
||||
props: {
|
||||
@ -129,54 +134,31 @@ export default {
|
||||
return this.$store.getters.getCircle(this.selectedCircle)
|
||||
},
|
||||
|
||||
groupedList() {
|
||||
// Group per userType
|
||||
return this.list.reduce(function(list, member) {
|
||||
const userType = member.userType
|
||||
list[userType] = list[userType] || []
|
||||
list[userType].push(member)
|
||||
return list
|
||||
}, Object.create(null))
|
||||
},
|
||||
|
||||
filteredList() {
|
||||
const groupList = CIRCLES_MEMBER_GROUPING.map((group) => {
|
||||
group.label = group.labelStandalone
|
||||
return group
|
||||
})
|
||||
return Object.keys(this.groupedList)
|
||||
// Object.keys returns string
|
||||
.map(type => parseInt(type, 10))
|
||||
// Map populated types to the group entry
|
||||
.map(type => groupList.find(group => group.type === type))
|
||||
// Removed undefined group
|
||||
.filter(group => group !== undefined)
|
||||
// Injecting headings
|
||||
.map(group => {
|
||||
return [{
|
||||
heading: true,
|
||||
...group,
|
||||
}, ...(this.groupedList[group.type] || [])]
|
||||
})
|
||||
// Merging sub-arrays
|
||||
.flat()
|
||||
},
|
||||
|
||||
hasMembers() {
|
||||
return this.filteredList.length > 0
|
||||
return this.groupedList.length > 0
|
||||
},
|
||||
|
||||
filteredPickerData() {
|
||||
return this.pickerData.filter(entity => {
|
||||
const type = SHARES_TYPES_MEMBER_MAP[entity.shareType]
|
||||
const list = this.groupedList[type]
|
||||
const list = this.list.filter(({ userType }) => userType === type)
|
||||
if (list) {
|
||||
return list.find(member => member.userId === entity.shareWith) === undefined
|
||||
return list.find((member) => member.userId === entity.shareWith) === undefined
|
||||
}
|
||||
// If the type doesn't exists, there is no member of this type
|
||||
return true
|
||||
})
|
||||
},
|
||||
|
||||
groupedList() {
|
||||
return CIRCLES_MEMBER_GROUPING
|
||||
.map(({ labelStandalone, type }) => ({
|
||||
type,
|
||||
label: labelStandalone,
|
||||
members: [...this.list.filter(({ userType }) => userType === type)],
|
||||
}))
|
||||
.filter(({ members }) => members.length > 0)
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
@ -253,7 +235,7 @@ export default {
|
||||
try {
|
||||
const members = await this.$store.dispatch('addMembersToCircle', { circleId: this.pickerCircle, selection })
|
||||
|
||||
if (members.length !== selection.length) {
|
||||
if (members.length < selection.length) {
|
||||
showWarning(t('contacts', 'Some members could not be added'))
|
||||
// TODO filter successful members and edit selection
|
||||
this.pickerSelection = {}
|
||||
@ -279,13 +261,14 @@ export default {
|
||||
this.pickerSelection = {}
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.members-list {
|
||||
.member-list {
|
||||
// Make virtual scroller scrollable
|
||||
max-height: 100%;
|
||||
max-width: 900px;
|
||||
overflow: auto;
|
||||
|
||||
&__new {
|
61
src/components/MemberList/MemberListGroup.vue
Normal file
61
src/components/MemberList/MemberListGroup.vue
Normal file
@ -0,0 +1,61 @@
|
||||
<!--
|
||||
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<script setup lang="ts">
|
||||
import type Member from '../../models/member'
|
||||
import MemberListItem from './MemberListItem.vue'
|
||||
|
||||
defineProps<{
|
||||
label: string
|
||||
type: number
|
||||
members: Member[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="member-list-group">
|
||||
<h4 :id="`member-list-group-${type}`"
|
||||
class="member-list-group__heading">
|
||||
{{ label }}
|
||||
</h4>
|
||||
<ul :aria-labelledby="`member-list-group-${type}`" class="member-list-group__list">
|
||||
<MemberListItem v-for="member in members"
|
||||
:key="member.singleId"
|
||||
:source="member" />
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.member-list-group {
|
||||
&__heading {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
padding-top: 22px;
|
||||
padding-inline-start: 8px;
|
||||
margin-bottom: 0;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 1.1rem;
|
||||
color: var(--color-primary-element);
|
||||
}
|
||||
|
||||
&__list {
|
||||
-webkit-columns: 2;
|
||||
-moz-columns: 2;
|
||||
columns: 2;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 700px) {
|
||||
.member-list-group__list {
|
||||
-webkit-columns: 1;
|
||||
-moz-columns: 1;
|
||||
columns: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -4,118 +4,116 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<span v-if="source.heading" class="members-list__heading">
|
||||
{{ source.label }}
|
||||
</span>
|
||||
|
||||
<ListItemIcon v-else
|
||||
:id="source.singleId"
|
||||
:avatar-size="avatarSize"
|
||||
:display-name="source.displayName"
|
||||
:icon-class="source.isUser ? null : 'icon-group-white'"
|
||||
:is-no-user="!source.isUser"
|
||||
:subname="levelName"
|
||||
<NcListItem compact
|
||||
:name="source.displayName"
|
||||
class="members-list__item">
|
||||
<!-- Accept invite -->
|
||||
<template v-if="!loading && isPendingApproval && circle.canManageMembers">
|
||||
<Actions>
|
||||
<ActionButton @click="acceptMember">
|
||||
<template #icon>
|
||||
<IconCheck :size="20" />
|
||||
</template>
|
||||
{{ t('contacts', 'Accept membership request') }}
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
<Actions>
|
||||
<ActionButton @click="deleteMember">
|
||||
<template #icon>
|
||||
<IconClose :size="20" />
|
||||
</template>
|
||||
{{ t('contacts', 'Reject membership request') }}
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
class="members-list-item">
|
||||
<template #icon>
|
||||
<NcAvatar disable-menu
|
||||
:size="avatarSize"
|
||||
:display-name="source.displayName"
|
||||
:is-no-user="!source.isUser" />
|
||||
</template>
|
||||
|
||||
<Actions v-else @close="onMenuClose">
|
||||
<ActionText v-if="loading" icon="icon-loading-small">
|
||||
<!-- Level -->
|
||||
<template #subname>
|
||||
{{ levelName }}
|
||||
</template>
|
||||
|
||||
<!-- Accept invite -->
|
||||
<template v-if="!loading && isPendingApproval && circle.canManageMembers" #extra-actions>
|
||||
<NcButton @click="acceptMember">
|
||||
<template #icon>
|
||||
<IconCheck :size="20" />
|
||||
</template>
|
||||
{{ t('contacts', 'Accept membership request') }}
|
||||
</NcButton>
|
||||
<NcButton @click="deleteMember">
|
||||
<template #icon>
|
||||
<IconClose :size="20" />
|
||||
</template>
|
||||
{{ t('contacts', 'Reject membership request') }}
|
||||
</NcButton>
|
||||
</template>
|
||||
|
||||
<template v-else #actions>
|
||||
<NcActionText v-if="loading" icon="icon-loading-small">
|
||||
{{ t('contacts', 'Loading …') }}
|
||||
</ActionText>
|
||||
</NcActionText>
|
||||
|
||||
<!-- Normal menu -->
|
||||
<template v-else>
|
||||
<!-- Level picker -->
|
||||
<template v-if="canChangeLevel">
|
||||
<ActionText>
|
||||
<NcActionText>
|
||||
{{ t('contacts', 'Manage level') }}
|
||||
<template #icon>
|
||||
<ShieldCheck :size="16" />
|
||||
<IconShieldCheck :size="16" />
|
||||
</template>
|
||||
</ActionText>
|
||||
<ActionButton v-for="level in availableLevelsChange"
|
||||
</NcActionText>
|
||||
<NcActionButton v-for="level in availableLevelsChange"
|
||||
:key="level"
|
||||
icon=""
|
||||
@click="changeLevel(level)">
|
||||
{{ levelChangeLabel(level) }}
|
||||
</ActionButton>
|
||||
</NcActionButton>
|
||||
|
||||
<ActionSeparator />
|
||||
<NcActionSeparator />
|
||||
</template>
|
||||
|
||||
<!-- Leave or delete member from circle -->
|
||||
<ActionButton v-if="isCurrentUser && !circle.isOwner" @click="deleteMember">
|
||||
<NcActionButton v-if="isCurrentUser && !circle.isOwner" @click="deleteMember">
|
||||
{{ t('contacts', 'Leave team') }}
|
||||
<template #icon>
|
||||
<ExitToApp :size="16" />
|
||||
<IconExitToApp :size="16" />
|
||||
</template>
|
||||
</ActionButton>
|
||||
<ActionButton v-else-if="canDelete" @click="deleteMember">
|
||||
</NcActionButton>
|
||||
<NcActionButton v-else-if="canDelete" @click="deleteMember">
|
||||
<template #icon>
|
||||
<IconDelete :size="20" />
|
||||
</template>
|
||||
{{ t('contacts', 'Remove member') }}
|
||||
</ActionButton>
|
||||
</NcActionButton>
|
||||
</template>
|
||||
</Actions>
|
||||
</ListItemIcon>
|
||||
</template>
|
||||
</NcListItem>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { CIRCLES_MEMBER_LEVELS, MemberLevels, MemberStatus } from '../../models/constants.ts'
|
||||
|
||||
import {
|
||||
NcActions as Actions,
|
||||
NcListItemIcon as ListItemIcon,
|
||||
NcActionSeparator as ActionSeparator,
|
||||
NcActionButton as ActionButton,
|
||||
NcActionText as ActionText,
|
||||
NcAvatar,
|
||||
NcListItem,
|
||||
NcActionSeparator,
|
||||
NcActionButton,
|
||||
NcActionText,
|
||||
} from '@nextcloud/vue'
|
||||
import IconDelete from 'vue-material-design-icons/Delete.vue'
|
||||
import IconCheck from 'vue-material-design-icons/Check.vue'
|
||||
import IconClose from 'vue-material-design-icons/Close.vue'
|
||||
|
||||
import ExitToApp from 'vue-material-design-icons/ExitToApp.vue'
|
||||
import ShieldCheck from 'vue-material-design-icons/ShieldCheck.vue'
|
||||
import IconDelete from 'vue-material-design-icons/Delete.vue'
|
||||
import IconExitToApp from 'vue-material-design-icons/ExitToApp.vue'
|
||||
import IconShieldCheck from 'vue-material-design-icons/ShieldCheck.vue'
|
||||
|
||||
import { changeMemberLevel } from '../../services/circles.ts'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import RouterMixin from '../../mixins/RouterMixin.js'
|
||||
|
||||
export default {
|
||||
name: 'MembersListItem',
|
||||
name: 'MemberListItem',
|
||||
|
||||
components: {
|
||||
Actions,
|
||||
ActionButton,
|
||||
ActionSeparator,
|
||||
ActionText,
|
||||
IconDelete,
|
||||
IconCheck,
|
||||
IconClose,
|
||||
ExitToApp,
|
||||
ListItemIcon,
|
||||
ShieldCheck,
|
||||
IconDelete,
|
||||
IconExitToApp,
|
||||
IconShieldCheck,
|
||||
NcListItem,
|
||||
NcActionButton,
|
||||
NcActionSeparator,
|
||||
NcActionText,
|
||||
NcAvatar,
|
||||
},
|
||||
|
||||
mixins: [RouterMixin],
|
||||
|
||||
props: {
|
||||
@ -342,32 +340,10 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.members-list__heading {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
padding-top: 22px;
|
||||
padding-left: 8px;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
pointer-events: none;
|
||||
color: var(--color-primary-element);
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.members-list__item {
|
||||
padding: 8px;
|
||||
<style lang="scss">
|
||||
.members-list-item {
|
||||
user-select: none;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 8px;
|
||||
border-radius: var(--border-radius-rounded);
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
background-color: var(--color-background-hover);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
@ -1,14 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "ES6",
|
||||
"moduleResolution": "node",
|
||||
"target": "ES6",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"target": "ESNext",
|
||||
"strictNullChecks": true,
|
||||
"sourceMap": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"declaration": true,
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
]
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
]
|
||||
}
|
||||
|
Reference in New Issue
Block a user