mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-04 22:06:06 +02:00
groups bulk management & fix vue warning (#1244)
* groups bulk management & fix vue warning * reset group selection state on edit_mode exit
This commit is contained in:
@@ -233,67 +233,65 @@
|
|||||||
style="margin-right: 5px; margin-top: 5px"
|
style="margin-right: 5px; margin-top: 5px"
|
||||||
v-text="userDialog.ref.$customTag"></el-tag>
|
v-text="userDialog.ref.$customTag"></el-tag>
|
||||||
<br />
|
<br />
|
||||||
<template v-for="badge in userDialog.ref.badges">
|
<el-tooltip v-for="badge in userDialog.ref.badges" :key="badge.badgeId" placement="top">
|
||||||
<el-tooltip :key="badge.badgeId" placement="top">
|
<template #content>
|
||||||
<template #content>
|
<span>{{ badge.badgeName }}</span>
|
||||||
|
<span v-if="badge.hidden"> (Hidden)</span>
|
||||||
|
</template>
|
||||||
|
<el-popover placement="right" width="300px" trigger="click">
|
||||||
|
<img
|
||||||
|
slot="reference"
|
||||||
|
class="x-link x-user-badge"
|
||||||
|
:src="badge.badgeImageUrl"
|
||||||
|
style="
|
||||||
|
flex: none;
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
border-radius: 3px;
|
||||||
|
object-fit: cover;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
"
|
||||||
|
:class="{ 'x-user-badge-hidden': badge.hidden }" />
|
||||||
|
<img
|
||||||
|
v-lazy="badge.badgeImageUrl"
|
||||||
|
class="x-link"
|
||||||
|
style="width: 300px"
|
||||||
|
@click="showFullscreenImageDialog(badge.badgeImageUrl)" />
|
||||||
|
<br />
|
||||||
|
<div style="display: block; width: 300px; word-break: normal">
|
||||||
<span>{{ badge.badgeName }}</span>
|
<span>{{ badge.badgeName }}</span>
|
||||||
<span v-if="badge.hidden"> (Hidden)</span>
|
|
||||||
</template>
|
|
||||||
<el-popover placement="right" width="300px" trigger="click">
|
|
||||||
<img
|
|
||||||
slot="reference"
|
|
||||||
class="x-link x-user-badge"
|
|
||||||
:src="badge.badgeImageUrl"
|
|
||||||
style="
|
|
||||||
flex: none;
|
|
||||||
height: 32px;
|
|
||||||
width: 32px;
|
|
||||||
border-radius: 3px;
|
|
||||||
object-fit: cover;
|
|
||||||
margin-top: 5px;
|
|
||||||
margin-right: 5px;
|
|
||||||
"
|
|
||||||
:class="{ 'x-user-badge-hidden': badge.hidden }" />
|
|
||||||
<img
|
|
||||||
v-lazy="badge.badgeImageUrl"
|
|
||||||
class="x-link"
|
|
||||||
style="width: 300px"
|
|
||||||
@click="showFullscreenImageDialog(badge.badgeImageUrl)" />
|
|
||||||
<br />
|
<br />
|
||||||
<div style="display: block; width: 300px; word-break: normal">
|
<span class="x-grey" style="font-size: 12px">{{
|
||||||
<span>{{ badge.badgeName }}</span>
|
badge.badgeDescription
|
||||||
|
}}</span>
|
||||||
|
<br />
|
||||||
|
<span
|
||||||
|
v-if="badge.assignedAt"
|
||||||
|
class="x-grey"
|
||||||
|
style="font-family: monospace; font-size: 12px">
|
||||||
|
{{ t('dialog.user.badges.assigned') }}:
|
||||||
|
{{ badge.assignedAt | formatDate('long') }}
|
||||||
|
</span>
|
||||||
|
<template v-if="userDialog.id === API.currentUser.id">
|
||||||
<br />
|
<br />
|
||||||
<span class="x-grey" style="font-size: 12px">{{
|
<el-checkbox
|
||||||
badge.badgeDescription
|
v-model="badge.hidden"
|
||||||
}}</span>
|
style="margin-top: 5px"
|
||||||
|
@change="toggleBadgeVisibility(badge)">
|
||||||
|
{{ t('dialog.user.badges.hidden') }}
|
||||||
|
</el-checkbox>
|
||||||
<br />
|
<br />
|
||||||
<span
|
<el-checkbox
|
||||||
v-if="badge.assignedAt"
|
v-model="badge.showcased"
|
||||||
class="x-grey"
|
style="margin-top: 5px"
|
||||||
style="font-family: monospace; font-size: 12px">
|
@change="toggleBadgeShowcased(badge)">
|
||||||
{{ t('dialog.user.badges.assigned') }}:
|
{{ t('dialog.user.badges.showcased') }}
|
||||||
{{ badge.assignedAt | formatDate('long') }}
|
</el-checkbox>
|
||||||
</span>
|
</template>
|
||||||
<template v-if="userDialog.id === API.currentUser.id">
|
</div>
|
||||||
<br />
|
</el-popover>
|
||||||
<el-checkbox
|
</el-tooltip>
|
||||||
v-model="badge.hidden"
|
|
||||||
style="margin-top: 5px"
|
|
||||||
@change="toggleBadgeVisibility(badge)">
|
|
||||||
{{ t('dialog.user.badges.hidden') }}
|
|
||||||
</el-checkbox>
|
|
||||||
<br />
|
|
||||||
<el-checkbox
|
|
||||||
v-model="badge.showcased"
|
|
||||||
style="margin-top: 5px"
|
|
||||||
@change="toggleBadgeShowcased(badge)">
|
|
||||||
{{ t('dialog.user.badges.showcased') }}
|
|
||||||
</el-checkbox>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</el-popover>
|
|
||||||
</el-tooltip>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 5px">
|
<div style="margin-top: 5px">
|
||||||
<span style="font-size: 12px" v-text="userDialog.ref.statusDescription"></span>
|
<span style="font-size: 12px" v-text="userDialog.ref.statusDescription"></span>
|
||||||
@@ -1151,12 +1149,53 @@
|
|||||||
<div v-loading="userDialog.isGroupsLoading" style="margin-top: 10px">
|
<div v-loading="userDialog.isGroupsLoading" style="margin-top: 10px">
|
||||||
<template v-if="userDialogGroupEditMode">
|
<template v-if="userDialogGroupEditMode">
|
||||||
<div class="x-friend-list" style="margin-top: 10px; margin-bottom: 15px; max-height: unset">
|
<div class="x-friend-list" style="margin-top: 10px; margin-bottom: 15px; max-height: unset">
|
||||||
|
|
||||||
|
<!-- Bulk actions dropdown (shown only in edit mode) -->
|
||||||
|
<el-dropdown trigger="click">
|
||||||
|
<el-button size="small" icon="el-icon-setting"
|
||||||
|
style="margin-right: 5px; height: 29px; padding: 7px 15px">
|
||||||
|
{{ t('dialog.group.actions.manage_selected') }}
|
||||||
|
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
|
</el-button>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item @click.native="bulkSetVisibility('visible')">
|
||||||
|
{{ t('dialog.group.actions.visibility_everyone') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click.native="bulkSetVisibility('friends')">
|
||||||
|
{{ t('dialog.group.actions.visibility_friends') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click.native="bulkSetVisibility('hidden')">
|
||||||
|
{{ t('dialog.group.actions.visibility_hidden') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item divided @click.native="bulkLeaveGroups">
|
||||||
|
<i class="el-icon-delete"></i>
|
||||||
|
{{ t('dialog.user.groups.leave_group_tooltip') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
|
||||||
|
<!-- Select All button -->
|
||||||
|
<el-button size="small"
|
||||||
|
:icon="userDialogGroupAllSelected ? 'el-icon-close' : 'el-icon-check'"
|
||||||
|
style="height: 29px; padding: 7px 15px" @click="selectAllGroups">
|
||||||
|
{{ userDialogGroupAllSelected ? t('dialog.group.actions.deselect_all') :
|
||||||
|
t('dialog.group.actions.select_all') }}
|
||||||
|
</el-button>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-for="group in userDialogGroupEditGroups"
|
v-for="group in userDialogGroupEditGroups"
|
||||||
:key="group.id"
|
:key="group.id"
|
||||||
class="x-friend-item x-friend-item-border"
|
class="x-friend-item x-friend-item-border"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@click="showGroupDialog(group.id)">
|
@click="showGroupDialog(group.id)">
|
||||||
|
|
||||||
|
<!-- Manual checkbox -->
|
||||||
|
<div style="margin-left: 5px; margin-right: 5px; transform: scale(0.8); transform-origin: left center;"
|
||||||
|
@click.stop>
|
||||||
|
<el-checkbox :checked="userDialogGroupEditSelectedGroupIds.includes(group.id)"
|
||||||
|
@change="() => toggleGroupSelection(group.id)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="margin-right: 3px; margin-left: 5px" @click.stop>
|
<div style="margin-right: 3px; margin-left: 5px" @click.stop>
|
||||||
<el-button
|
<el-button
|
||||||
size="mini"
|
size="mini"
|
||||||
@@ -2014,8 +2053,11 @@
|
|||||||
const userDialogTabsRef = ref(null);
|
const userDialogTabsRef = ref(null);
|
||||||
const userDialogRef = ref(null);
|
const userDialogRef = ref(null);
|
||||||
|
|
||||||
const userDialogGroupEditMode = ref(false);
|
const userDialogGroupEditMode = ref(false); // whether edit mode is active
|
||||||
const userDialogGroupEditGroups = ref([]);
|
const userDialogGroupEditGroups = ref([]); // editable group list
|
||||||
|
const userDialogGroupAllSelected = ref(false);
|
||||||
|
const userDialogGroupEditSelectedGroupIds = ref([]); // selected groups in edit mode
|
||||||
|
|
||||||
const userDialogLastActiveTab = ref('');
|
const userDialogLastActiveTab = ref('');
|
||||||
const userDialogLastGroup = ref('');
|
const userDialogLastGroup = ref('');
|
||||||
const userDialogLastAvatar = ref('');
|
const userDialogLastAvatar = ref('');
|
||||||
@@ -3043,6 +3085,8 @@
|
|||||||
async function exitEditModeCurrentUserGroups() {
|
async function exitEditModeCurrentUserGroups() {
|
||||||
userDialogGroupEditMode.value = false;
|
userDialogGroupEditMode.value = false;
|
||||||
userDialogGroupEditGroups.value = [];
|
userDialogGroupEditGroups.value = [];
|
||||||
|
userDialogGroupEditSelectedGroupIds.value = [];
|
||||||
|
userDialogGroupAllSelected.value = false;
|
||||||
await sortCurrentUserGroups();
|
await sortCurrentUserGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3070,6 +3114,45 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select all groups currently in the editable list by collecting their IDs
|
||||||
|
function selectAllGroups() {
|
||||||
|
const allSelected = userDialogGroupEditSelectedGroupIds.value.length === userDialogGroupEditGroups.value.length;
|
||||||
|
|
||||||
|
// First update selection state
|
||||||
|
userDialogGroupEditSelectedGroupIds.value = allSelected ? [] : userDialogGroupEditGroups.value.map(g => g.id);
|
||||||
|
userDialogGroupAllSelected.value = !allSelected;
|
||||||
|
|
||||||
|
// Toggle editMode off and back on to force checkbox UI update
|
||||||
|
userDialogGroupEditMode.value = false;
|
||||||
|
nextTick(() => {
|
||||||
|
userDialogGroupEditMode.value = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the given visibility to all selected groups
|
||||||
|
async function bulkSetVisibility(newVisibility) {
|
||||||
|
for (const groupId of userDialogGroupEditSelectedGroupIds.value) {
|
||||||
|
setGroupVisibility(groupId, newVisibility);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leave (remove user from) all selected groups
|
||||||
|
function bulkLeaveGroups() {
|
||||||
|
for (const groupId of userDialogGroupEditSelectedGroupIds.value) {
|
||||||
|
leaveGroupPrompt(groupId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle individual group selection for bulk actions
|
||||||
|
function toggleGroupSelection(groupId) {
|
||||||
|
const index = userDialogGroupEditSelectedGroupIds.value.indexOf(groupId)
|
||||||
|
if (index === -1) {
|
||||||
|
userDialogGroupEditSelectedGroupIds.value.push(groupId)
|
||||||
|
} else {
|
||||||
|
userDialogGroupEditSelectedGroupIds.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function moveGroupUp(groupId) {
|
function moveGroupUp(groupId) {
|
||||||
const index = props.inGameGroupOrder.indexOf(groupId);
|
const index = props.inGameGroupOrder.indexOf(groupId);
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
|
|||||||
@@ -1019,6 +1019,9 @@
|
|||||||
"unsubscribe": "Unsubscribe From Announcements",
|
"unsubscribe": "Unsubscribe From Announcements",
|
||||||
"subscribe": "Subscribe To Announcements",
|
"subscribe": "Subscribe To Announcements",
|
||||||
"invite_to_group": "Invite To Group",
|
"invite_to_group": "Invite To Group",
|
||||||
|
"manage_selected": "Manage Selected Groups",
|
||||||
|
"select_all": "Select All",
|
||||||
|
"deselect_all": "Deselect All",
|
||||||
"visibility_everyone": "Visibility Everyone",
|
"visibility_everyone": "Visibility Everyone",
|
||||||
"visibility_friends": "Visibility Friends",
|
"visibility_friends": "Visibility Friends",
|
||||||
"visibility_hidden": "Visibility Hidden",
|
"visibility_hidden": "Visibility Hidden",
|
||||||
|
|||||||
Reference in New Issue
Block a user