Group change notification

This commit is contained in:
Natsumi
2024-04-18 01:46:52 +12:00
parent de8a7cb98c
commit 0587628856
6 changed files with 326 additions and 41 deletions

View File

@@ -1650,6 +1650,26 @@ speechSynthesis.getVoices();
$app.updateCurrentUserLocation();
};
API.applyPresenceGroups = function (ref) {
var groups = ref.presence?.groups;
if (!groups) {
console.error('API.applyPresenceGroups: invalid groups', ref);
return;
}
// update group list
for (var groupId of groups) {
if (!this.currentUserGroups.has(groupId)) {
$app.onGroupJoined(groupId);
}
}
for (var groupId of this.currentUserGroups.keys()) {
if (!groups.includes(groupId)) {
$app.onGroupLeft(groupId);
}
}
};
API.applyCurrentUser = function (json) {
var ref = this.currentUser;
if (this.isLoggedIn) {
@@ -1673,19 +1693,7 @@ speechSynthesis.getVoices();
this.applyUserLanguage(ref);
this.applyPresenceLocation(ref);
this.applyQueuedInstance(ref.queuedInstance);
// update group list
if (json.presence?.groups) {
for (var groupId of json.presence.groups) {
if (!this.currentUserGroups.has(groupId)) {
$app.onGroupJoined(groupId);
}
}
for (var groupId of this.currentUserGroups.keys()) {
if (!json.presence.groups.includes(groupId)) {
$app.onGroupLeft(groupId);
}
}
}
this.applyPresenceGroups(ref);
} else {
ref = {
acceptedPrivacyVersion: 0,
@@ -1790,6 +1798,7 @@ speechSynthesis.getVoices();
this.applyUserTrustLevel(ref);
this.applyUserLanguage(ref);
this.applyPresenceLocation(ref);
this.applyPresenceGroups(ref);
this.currentUser = ref;
this.isLoggedIn = true;
this.$emit('LOGIN', {
@@ -3478,6 +3487,11 @@ speechSynthesis.getVoices();
API.$on('NOTIFICATION:V2', function (args) {
var json = args.json;
json.created_at = json.createdAt;
if (json.title && json.message) {
json.message = `${json.title}, ${json.message}`;
} else if (json.title) {
json.message = json.title;
}
this.$emit('NOTIFICATION', {
json,
params: {
@@ -3585,6 +3599,21 @@ speechSynthesis.getVoices();
});
};
API.sendInviteGalleryPhoto = function (params, receiverUserId) {
return this.call(`invite/${receiverUserId}/photo`, {
method: 'POST',
params
}).then((json) => {
var args = {
json,
params,
receiverUserId
};
this.$emit('NOTIFICATION:INVITE:GALLERYPHOTO:SEND', args);
return args;
});
};
API.sendRequestInvite = function (params, receiverUserId) {
return this.call(`requestInvite/${receiverUserId}`, {
method: 'POST',
@@ -4987,6 +5016,7 @@ speechSynthesis.getVoices();
case 'group-role-updated':
var groupId = content.role.groupId;
API.getGroup({ groupId, includeRoles: true });
console.log('group-role-updated', content);
// content {
@@ -5006,6 +5036,7 @@ speechSynthesis.getVoices();
case 'group-member-updated':
var groupId = content.member.groupId;
API.getGroup({ groupId, includeRoles: true });
$app.onGroupJoined(groupId);
console.log('group-member-updated', content);
@@ -6665,6 +6696,9 @@ speechSynthesis.getVoices();
`${noty.previousDisplayName} changed their name to ${noty.displayName}`
);
break;
case 'groupChange':
this.speak(`${noty.senderUsername} ${noty.message}`);
break;
case 'group.announcement':
this.speak(noty.message);
break;
@@ -6890,6 +6924,14 @@ speechSynthesis.getVoices();
image
);
break;
case 'groupChange':
AppApi.XSNotification(
'VRCX',
`${noty.senderUsername}: ${noty.message}`,
timeout,
image
);
break;
case 'group.announcement':
AppApi.XSNotification('VRCX', noty.message, timeout, image);
break;
@@ -7214,6 +7256,16 @@ speechSynthesis.getVoices();
image
);
break;
case 'groupChange':
AppApi.OVRTNotification(
playOvrtHudNotifications,
playOvrtWristNotifications,
'VRCX',
`${noty.senderUsername}: ${noty.message}`,
timeout,
image
);
break;
case 'group.announcement':
AppApi.OVRTNotification(
playOvrtHudNotifications,
@@ -7559,6 +7611,13 @@ speechSynthesis.getVoices();
image
);
break;
case 'groupChange':
AppApi.DesktopNotification(
noty.senderUsername,
noty.message,
image
);
break;
case 'group.announcement':
AppApi.DesktopNotification(
'Group Announcement',
@@ -9863,6 +9922,7 @@ speechSynthesis.getVoices();
// eslint-disable-next-line require-atomic-updates
$app.notificationTable.data = await database.getNotifications();
await this.refreshNotifications();
await $app.loadCurrentUserGroups();
await $app.getCurrentUserGroups();
try {
if (
@@ -15530,6 +15590,7 @@ speechSynthesis.getVoices();
Unfriend: 'On',
DisplayName: 'VIP',
TrustLevel: 'VIP',
groupChange: 'On',
'group.announcement': 'On',
'group.informative': 'On',
'group.invite': 'On',
@@ -15569,6 +15630,7 @@ speechSynthesis.getVoices();
Unfriend: 'On',
DisplayName: 'Friends',
TrustLevel: 'Friends',
groupChange: 'On',
'group.announcement': 'On',
'group.informative': 'On',
'group.invite': 'On',
@@ -15632,6 +15694,10 @@ speechSynthesis.getVoices();
$app.data.sharedFeedFilters.noty.External = 'On';
$app.data.sharedFeedFilters.wrist.External = 'On';
}
if (!$app.data.sharedFeedFilters.noty.groupChange) {
$app.data.sharedFeedFilters.noty.groupChange = 'On';
$app.data.sharedFeedFilters.wrist.groupChange = 'On';
}
$app.data.trustColor = JSON.parse(
await configRepository.getString(
@@ -21069,7 +21135,7 @@ speechSynthesis.getVoices();
API.$on('VRCPLUSICON:ADD', function (args) {
if (Object.keys($app.VRCPlusIconsTable).length !== 0) {
$app.VRCPlusIconsTable.push(args.json);
$app.VRCPlusIconsTable.unshift(args.json);
}
});
@@ -21105,6 +21171,7 @@ speechSynthesis.getVoices();
};
$app.methods.clearInviteImageUpload = function () {
this.clearImageGallerySelect();
var buttonList = document.querySelectorAll('.inviteImageUploadButton');
buttonList.forEach((button) => (button.value = ''));
this.uploadImage = '';
@@ -24330,18 +24397,15 @@ speechSynthesis.getVoices();
mutualGroups: [],
remainingGroups: []
};
var params = {
n: 100,
offset: 0,
userId
};
var args = await API.getGroups(params);
var args = await API.getGroups({ userId });
if (userId === API.currentUser.id) {
// update current user groups
API.currentUserGroups.clear();
args.json.forEach((group) => {
API.currentUserGroups.set(group.id, group);
var ref = API.applyGroup(group);
API.currentUserGroups.set(group.id, ref);
});
this.saveCurrentUserGroups();
}
this.userGroups.groups = args.json;
for (var i = 0; i < args.json.length; ++i) {
@@ -24370,11 +24434,13 @@ speechSynthesis.getVoices();
};
$app.methods.getCurrentUserGroups = async function () {
var args = await API.getGroups({ n: 100, userId: API.currentUser.id });
var args = await API.getGroups({ userId: API.currentUser.id });
API.currentUserGroups.clear();
args.json.forEach((group) => {
API.currentUserGroups.set(group.id, group);
var ref = API.applyGroup(group);
API.currentUserGroups.set(group.id, ref);
});
this.saveCurrentUserGroups();
};
$app.methods.sortCurrentUserGroups = function () {
@@ -24556,7 +24622,7 @@ speechSynthesis.getVoices();
API.$on('GALLERYIMAGE:ADD', function (args) {
if (Object.keys($app.galleryTable).length !== 0) {
$app.galleryTable.push(args.json);
$app.galleryTable.unshift(args.json);
}
});
@@ -24673,11 +24739,12 @@ speechSynthesis.getVoices();
API.$on('EMOJI:ADD', function (args) {
if (Object.keys($app.emojiTable).length !== 0) {
$app.emojiTable.push(args.json);
$app.emojiTable.unshift(args.json);
}
});
$app.data.emojiAnimFps = 5;
$app.data.emojiFrameCountOptions = [4, 16, 64];
$app.data.emojiAnimFps = 15;
$app.data.emojiAnimFrameCount = 4;
$app.data.emojiAnimType = false;
$app.data.emojiAnimationStyle = 'Stop';
@@ -28661,6 +28728,39 @@ speechSynthesis.getVoices();
};
this.cachedGroups.set(ref.id, ref);
} else {
if (this.currentUserGroups.has(ref.id)) {
// compare group props
if (ref.ownerId && ref.ownerId !== json.ownerId) {
// owner changed
$app.groupOwnerChange(json, ref.ownerId, json.ownerId);
}
if (ref.name && ref.name !== json.name) {
// name changed
$app.groupChange(
json,
`Name changed from ${ref.name} to ${json.name}`
);
}
if (ref.myMember?.roleIds && json.myMember?.roleIds) {
var oldRoleIds = ref.myMember.roleIds;
var newRoleIds = json.myMember.roleIds;
if (
oldRoleIds.length !== newRoleIds.length ||
!oldRoleIds.every(
(value, index) => value === newRoleIds[index]
)
) {
// roleIds changed
$app.groupRoleChange(
json,
ref.roles,
json.roles,
oldRoleIds,
newRoleIds
);
}
}
}
Object.assign(ref, json);
}
ref.rules = $app.replaceBioSymbols(ref.rules);
@@ -28671,6 +28771,130 @@ speechSynthesis.getVoices();
return ref;
};
$app.methods.groupOwnerChange = async function (ref, oldUserId, newUserId) {
var oldUser = await API.getCachedUser({
userId: oldUserId
});
var newUser = await API.getCachedUser({
userId: newUserId
});
var oldDisplayName = oldUser?.ref?.displayName;
var newDisplayName = newUser?.ref?.displayName;
this.groupChange(
ref,
`Owner changed from ${oldDisplayName} to ${newDisplayName}`
);
};
$app.methods.groupRoleChange = function (
ref,
oldRoles,
newRoles,
oldRoleIds,
newRoleIds
) {
// check for removed/added roleIds
for (var roleId of oldRoleIds) {
if (!newRoleIds.includes(roleId)) {
var roleName = '';
var role = oldRoles.find((fineRole) => fineRole.id === roleId);
if (role) {
roleName = role.name;
}
this.groupChange(ref, `Role ${roleName} removed`);
}
}
for (var roleId of newRoleIds) {
if (!oldRoleIds.includes(roleId)) {
var roleName = '';
var role = newRoles.find((fineRole) => fineRole.id === roleId);
if (role) {
roleName = role.name;
}
this.groupChange(ref, `Role ${roleName} added`);
}
}
};
$app.methods.groupChange = function (ref, message) {
// oh the level of cursed for compibility
var json = {
id: Math.random().toString(36),
type: 'groupChange',
senderUserId: ref.id,
senderUsername: ref.name,
message,
created_at: new Date().toJSON()
};
API.$emit('NOTIFICATION', {
json,
params: {
notificationId: json.id
}
});
// delay to wait for json to be assigned to ref
workerTimers.setTimeout(this.saveCurrentUserGroups, 100);
};
$app.methods.saveCurrentUserGroups = function () {
var groups = [];
for (var ref of API.currentUserGroups.values()) {
groups.push({
id: ref.id,
name: ref.name,
ownerId: ref.ownerId,
roles: ref.roles,
roleIds: ref.myMember?.roleIds
});
}
configRepository.setString(
`VRCX_currentUserGroups_${API.currentUser.id}`,
JSON.stringify(groups)
);
};
$app.methods.loadCurrentUserGroups = async function () {
if (
!(await configRepository.getString(
`VRCX_currentUserGroups_${API.currentUser.id}`
))
) {
// fetch every group with roles for storing and comparing later
for (var group of API.currentUserGroups.values()) {
await API.getGroup({
groupId: group.id,
includeRoles: true
});
}
this.saveCurrentUserGroups();
return;
}
var groups = JSON.parse(
await configRepository.getString(
`VRCX_currentUserGroups_${API.currentUser.id}`,
'[]'
)
);
API.cachedGroups.clear();
API.currentUserGroups.clear();
for (var group of groups) {
var ref = {
id: group.id,
name: group.name,
iconUrl: '',
ownerId: group.ownerId,
roles: group.roles,
myMember: {
roleIds: group.roleIds
}
};
API.cachedGroups.set(group.id, ref);
API.currentUserGroups.set(group.id, ref);
}
};
API.applyGroupMember = function (json) {
if (typeof json.user !== 'undefined') {
var ref = this.cachedUsers.get(json.user.id);
@@ -29058,7 +29282,12 @@ speechSynthesis.getVoices();
iconUrl: ''
});
if (this.friendLogInitStatus) {
API.getGroup({ groupId });
API.getGroup({ groupId, includeRoles: true }).then((args) => {
var ref = API.applyGroup(args.json);
API.currentUserGroups.set(groupId, ref);
this.saveCurrentUserGroups();
return args;
});
}
}
};
@@ -29068,6 +29297,9 @@ speechSynthesis.getVoices();
this.showGroupDialog(groupId);
}
API.currentUserGroups.delete(groupId);
API.getCachedGroup({ groupId }).then((args) => {
this.groupChange(args.ref, 'Left group');
});
};
// group search
@@ -29473,6 +29705,9 @@ speechSynthesis.getVoices();
return;
}
var data = link.split(':');
if (!data.length) {
return;
}
switch (data[0]) {
case 'group':
this.showGroupDialog(data[1]);
@@ -29773,23 +30008,31 @@ speechSynthesis.getVoices();
$app.data.gallerySelectDialog = {
visible: false,
destenationFeild: ''
selectedFileId: '',
selectedImageUrl: ''
};
$app.methods.showGallerySelectDialog = function (destenationFeild) {
$app.methods.showGallerySelectDialog = function () {
this.$nextTick(() => adjustDialogZ(this.$refs.gallerySelectDialog.$el));
var D = this.gallerySelectDialog;
D.destenationFeild = destenationFeild;
D.visible = true;
this.refreshGalleryTable();
};
$app.methods.selectImageGallerySelect = function (imageUrl, fileId) {
var D = this.gallerySelectDialog;
D.selectedFileId = fileId;
D.selectedImageUrl = imageUrl;
D.visible = false;
console.log(imageUrl, fileId);
};
$app.methods.clearImageGallerySelect = function () {
var D = this.gallerySelectDialog;
D.selectedFileId = '';
D.selectedImageUrl = '';
};
$app.methods.reportUserForHacking = function (userId) {
API.reportUser({
userId,

View File

@@ -862,7 +862,7 @@ html
el-button(:type="avatarDialog.isBlocked ? 'danger' : 'default'" icon="el-icon-more" circle style="margin-left:5px")
el-dropdown-menu(#default="dropdown")
el-dropdown-item(icon="el-icon-refresh" command="Refresh") {{ $t('dialog.avatar.actions.refresh') }}
el-dropdown-item(icon="el-icon-check" command="Select Avatar") {{ $t('dialog.avatar.actions.select') }}
el-dropdown-item(icon="el-icon-check" :disabled="API.currentUser.currentAvatar === avatarDialog.id" command="Select Avatar") {{ $t('dialog.avatar.actions.select') }}
el-dropdown-item(v-if="/quest/.test(avatarDialog.ref.tags)" icon="el-icon-check" command="Select Fallback Avatar") {{ $t('dialog.avatar.actions.select_fallback') }}
el-dropdown-item(v-if="avatarDialog.isBlocked" icon="el-icon-circle-check" command="Unblock Avatar" style="color:#F56C6C") {{ $t('dialog.avatar.actions.unblock') }}
el-dropdown-item(v-else icon="el-icon-circle-close" command="Block Avatar") {{ $t('dialog.avatar.actions.block') }}
@@ -1839,6 +1839,11 @@ html
el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }}
el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }}
el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }}
.toggle-item
span.toggle-name Group Change
el-radio-group(v-model="sharedFeedFilters.noty.groupChange" size="mini" @change="saveSharedFeedFilters")
el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }}
el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }}
.toggle-item
span.toggle-name Group Announcement
el-radio-group(v-model="sharedFeedFilters.noty['group.announcement']" size="mini" @change="saveSharedFeedFilters")
@@ -2066,6 +2071,11 @@ html
el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }}
el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }}
el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }}
.toggle-item
span.toggle-name Group Change
el-radio-group(v-model="sharedFeedFilters.wrist.groupChange" size="mini" @change="saveSharedFeedFilters")
el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }}
el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }}
.toggle-item
span.toggle-name Group Announcement
el-radio-group(v-model="sharedFeedFilters.wrist['group.announcement']" size="mini" @change="saveSharedFeedFilters")
@@ -2253,6 +2263,14 @@ html
//- dialog Table: Send Invite Message
el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteDialog" :visible.sync="sendInviteDialogVisible" :title="$t('dialog.invite_message.header')" width="800px")
template(v-if="API.currentUser.$isVRCPlus")
//- template(v-if="gallerySelectDialog.selectedFileId")
//- div(style="display:inline-block;flex:none;margin-right:5px")
//- el-popover(placement="right" width="500px" trigger="click")
//- img.x-link(slot="reference" v-lazy="gallerySelectDialog.selectedImageUrl" style="flex:none;width:60px;height:60px;border-radius:4px;object-fit:cover")
//- img.x-link(v-lazy="gallerySelectDialog.selectedImageUrl" style="height:500px" @click="showFullscreenImageDialog(gallerySelectDialog.selectedImageUrl)")
//- el-button(size="mini" @click="clearImageGallerySelect" style="vertical-align:top") {{ $t('dialog.invite_message.clear_selected_image') }}
//- template(v-else)
//- el-button(size="mini" @click="showGallerySelectDialog" style="margin-right:5px") {{ $t('dialog.invite_message.select_image') }}
input.inviteImageUploadButton(type="file" accept="image/png" @change="inviteImageUpload")
data-tables(v-if="sendInviteDialogVisible" v-bind="inviteMessageTable" @row-click="showSendInviteConfirmDialog" style="margin-top:10px;cursor:pointer")
el-table-column(:label="$t('table.profile.invite_messages.slot')" prop="slot" sortable="custom" width="70")
@@ -2394,8 +2412,11 @@ html
template(v-if="emojiAnimType")
span(style="margin-right:10px") {{ $t('dialog.gallery_icons.emoji_animation_fps') }}
el-input(v-model="emojiAnimFps" :min="1" :max="64" size="small" style="width:48px;margin-right:10px")
span(style="margin-right:10px") {{ $t('dialog.gallery_icons.emoji_animation_frame_count') }}
el-input(v-model="emojiAnimFrameCount" :min="1" :max="64" size="small" style="width:48px;margin-right:10px")
el-dropdown(@click.native.stop trigger="click" size="small" style="margin-right:5px")
el-button(size="mini")
span {{ $t('dialog.gallery_icons.emoji_animation_frame_count') }} {{ emojiAnimFrameCount }} #[i.el-icon-arrow-down.el-icon--right]
el-dropdown-menu(#default="dropdown")
el-dropdown-item(v-for="(item) in emojiFrameCountOptions" v-text="item" @click.native="emojiAnimFrameCount = item")
br
span {{ $t('dialog.gallery_icons.flipbook_info') }}
br

View File

@@ -1168,6 +1168,8 @@
"invite_message": {
"header": "Send Invite Message",
"confirmation": "Are you sure you want to send?",
"select_image": "Select Image",
"clear_selected_image": "Clear Selected Image",
"cancel": "Cancel",
"refresh": "Refresh",
"confirm": "Confirm"
@@ -1214,7 +1216,7 @@
"emoji_animation_type": "Animated Emoji",
"emoji_animation_fps": "FPS:",
"emoji_animation_frame_count": "Frame Count:",
"flipbook_info": "Select a flipbook texture PNG to use as an animated emoji"
"flipbook_info": "Select a 1024x1024 PNG spritesheet to use as an animated emoji (max FPS 64)"
},
"change_content_image": {
"avatar": "Change Avatar Image",
@@ -1571,7 +1573,7 @@
"notification": {
"date": "Date",
"type": "Type",
"user": "User",
"user_group": "User/Group",
"photo": "Photo",
"message": "Message",
"action": "Action"

View File

@@ -4,7 +4,7 @@ mixin notificationsTab()
template(#tool)
div(style="margin:0 0 10px;display:flex;align-items:center")
el-select(v-model="notificationTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" :placeholder="$t('view.notification.filter_placeholder')")
el-option(v-once v-for="type in ['requestInvite', 'invite', 'requestInviteResponse', 'inviteResponse', 'friendRequest', 'hiddenFriendRequest', 'message', 'group.announcement', 'group.informative', 'group.invite', 'group.joinRequest', 'group.queueReady', 'moderation.warning.group', 'instance.closed']" :key="type" :label="type" :value="type")
el-option(v-once v-for="type in ['requestInvite', 'invite', 'requestInviteResponse', 'inviteResponse', 'friendRequest', 'hiddenFriendRequest', 'message', 'groupChange', 'group.announcement', 'group.informative', 'group.invite', 'group.joinRequest', 'group.queueReady', 'moderation.warning.group', 'instance.closed']" :key="type" :label="type" :value="type")
el-input(v-model="notificationTable.filters[1].value" :placeholder="$t('view.notification.search_placeholder')" style="flex:none;width:150px;margin:0 10px")
el-tooltip(placement="bottom" :content="$t('view.notification.refresh_tooltip')" :disabled="hideTooltips")
el-button(type="default" :loading="API.isNotificationsLoading" @click="API.refreshNotifications()" icon="el-icon-refresh" circle style="flex:none")
@@ -28,9 +28,16 @@ mixin notificationsTab()
el-tooltip(placement="top" :content="scope.row.linkText" :disabled="hideTooltips")
span.x-link(v-text="scope.row.type" @click="openNotificationLink(scope.row.link)")
span(v-else v-text="scope.row.type")
el-table-column(:label="$t('table.notification.user')" prop="senderUsername" width="150")
el-table-column(:label="$t('table.notification.user_group')" prop="senderUsername" width="150")
template(v-once #default="scope")
span.x-link(v-text="scope.row.senderUsername" @click="showUserDialog(scope.row.senderUserId)")
template(v-if="scope.row.type === 'groupChange'")
span.x-link(v-text="scope.row.senderUsername" @click="showGroupDialog(scope.row.senderUserId)")
template(v-else-if="scope.row.senderUserId")
span.x-link(v-text="scope.row.senderUsername" @click="showUserDialog(scope.row.senderUserId)")
template(v-else-if="scope.row.link && scope.row.data?.groupName")
span.x-link(v-text="scope.row.data?.groupName" @click="openNotificationLink(scope.row.link)")
template(v-else-if="scope.row.link")
span.x-link(v-text="scope.row.linkText" @click="openNotificationLink(scope.row.link)")
el-table-column(:label="$t('table.notification.photo')" width="100" prop="photo")
template(v-once #default="scope")
template(v-if="scope.row.details && scope.row.details.imageUrl")
@@ -46,8 +53,7 @@ mixin notificationsTab()
span.x-link(v-if="scope.row.type === 'invite'" @click="showWorldDialog(scope.row.details.worldId)")
location(v-if="scope.row.details" :location="scope.row.details.worldId" :hint="scope.row.details.worldName" :grouphint="scope.row.details.groupName" :link="false")
br
span(v-if="scope.row.message && scope.row.message !== `This is a generated invite to ${scope.row.details?.worldName}`" v-text="scope.row.message")
span(v-else-if="scope.row.title") {{ scope.row.title }}, {{ scope.row.message }}
span(v-else-if="scope.row.message && scope.row.message !== `This is a generated invite to ${scope.row.details?.worldName}`" v-text="scope.row.message")
span(v-else-if='scope.row.details && scope.row.details.inviteMessage' v-text="scope.row.details.inviteMessage")
span(v-else-if='scope.row.details && scope.row.details.requestMessage' v-text="scope.row.details.requestMessage")
span(v-else-if='scope.row.details && scope.row.details.responseMessage' v-text="scope.row.details.responseMessage")
@@ -88,7 +94,7 @@ mixin notificationsTab()
template(v-else-if="scope.row.type === 'group.informative'")
el-tooltip(placement="top" content="Dismiss" :disabled="hideTooltips")
el-button(type="text" icon="el-icon-check" size="mini" style="margin-left:5px" @click="sendNotificationResponse(scope.row.id, scope.row.responses, 'delete')")
template(v-if="scope.row.type !== 'requestInviteResponse' && scope.row.type !== 'inviteResponse' && scope.row.type !== 'message' && !scope.row.type.includes('group.') && !scope.row.type.includes('moderation.') && !scope.row.type.includes('instance.')")
template(v-if="scope.row.type !== 'requestInviteResponse' && scope.row.type !== 'inviteResponse' && scope.row.type !== 'message' && scope.row.type !== 'groupChange' && !scope.row.type.includes('group.') && !scope.row.type.includes('moderation.') && !scope.row.type.includes('instance.')")
el-tooltip(placement="top" content="Decline" :disabled="hideTooltips")
el-button(type="text" icon="el-icon-close" size="mini" style="margin-left:5px" @click="hideNotification(scope.row)")
template(v-if="scope.row.type === 'group.queueReady'")

View File

@@ -582,6 +582,9 @@ Vue.component('marquee-text', MarqueeText);
case 'DisplayName':
text = `<strong>${noty.previousDisplayName}</strong> changed their name to ${noty.displayName}`;
break;
case 'groupChange':
text = `<strong>${noty.senderUsername}</strong> ${noty.message}`;
break;
case 'group.announcement':
text = noty.message;
break;

View File

@@ -119,6 +119,11 @@ html
span.extra
span.time {{ feed.created_at | formatDate }}
| 🤝 #[span.name(v-text="feed.displayName")] {{ feed.previousTrustLevel }} #[i.el-icon-right] {{ feed.trustLevel }}
div(v-else-if="feed.type === 'groupChange'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🏷️ #[span.name(v-text="feed.senderUsername")] #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.announcement'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
@@ -334,6 +339,11 @@ html
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName")] trust level is now {{ feed.trustLevel }}
div(v-else-if="feed.type === 'groupChange'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.senderUsername")] #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.announcement'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra