diff --git a/.vscode/settings.json b/.vscode/settings.json index da190865..eaa7fd9d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "i18n-ally.localesPaths": ["html/src/localization/strings"], + "i18n-ally.localesPaths": ["html/src/localization"], "i18n-ally.keystyle": "nested", "i18n-ally.sourceLanguage": "en", "editor.defaultFormatter": "esbenp.prettier-vscode", diff --git a/html/src/app.js b/html/src/app.js index eb201891..a5214d28 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -1241,7 +1241,6 @@ speechSynthesis.getVoices(); template: '{{ username }}', props: { - username: String, userid: String, location: String, key: Number @@ -13792,7 +13791,7 @@ speechSynthesis.getVoices(); filter.value.some((v) => v === row.type) }, { - prop: 'senderUsername', + prop: ['senderUsername', 'message'], value: '' } ], @@ -26523,14 +26522,14 @@ speechSynthesis.getVoices(); ); ref.$msgBox.message = `You are in position ${ref.position} of ${ref.queueSize} in the queue for ${displayLocation} `; API.queuedInstances.set(instanceId, ref); - workerTimers.setTimeout(this.instanceQueueTimeout, 900000); // 15mins + workerTimers.setTimeout(this.instanceQueueTimeout, 3600000); }; $app.methods.instanceQueueTimeout = function () { - // remove instance from queue after 15mins of inactivity + // remove instance from queue after 1hour of inactivity API.queuedInstances.forEach((ref) => { - // 14mins - if (Date.now() - ref.updatedAt > 840000) { + // 59mins + if (Date.now() - ref.updatedAt > 3540000) { ref.$msgBox.close(); API.queuedInstances.delete(ref.location); } @@ -26868,19 +26867,66 @@ speechSynthesis.getVoices(); groupId: string } */ - API.getGroupAnnouncement = function (params) { - return this.call(`groups/${params.groupId}/announcement`, { - method: 'GET' + // API.getGroupAnnouncement = function (params) { + // return this.call(`groups/${params.groupId}/announcement`, { + // method: 'GET' + // }).then((json) => { + // var args = { + // json, + // params + // }; + // this.$emit('GROUP:ANNOUNCEMENT', args); + // return args; + // }); + // }; + + /* + params: { + groupId: string, + n: number, + offset: number + } + */ + API.getGroupPosts = function (params) { + return this.call(`groups/${params.groupId}/posts`, { + method: 'GET', + params }).then((json) => { var args = { json, params }; - this.$emit('GROUP:ANNOUNCEMENT', args); + this.$emit('GROUP:POSTS', args); return args; }); }; + /* + params: { + groupId: string + } + */ + API.getAllGroupPosts = async function (params) { + var posts = []; + var offset = 0; + var n = 100; + var total = 0; + do { + var args = await this.getGroupPosts({ + groupId: params.groupId, + n, + offset + }); + posts = posts.concat(args.json.posts); + total = args.json.total; + offset += n; + } while (offset < total); + return { + posts, + params + }; + }; + /* params: { groupId: string, @@ -27263,14 +27309,16 @@ speechSynthesis.getVoices(); id: '', inGroup: false, ownerDisplayName: '', - announcementDisplayName: '', ref: {}, announcement: {}, + posts: [], + postsFiltered: [], members: [], instances: [], memberRoles: [], memberFilter: $app.data.groupDialogFilterOptions.everyone, memberSortOrder: $app.data.groupDialogSortingOptions.joinedAtDesc, + postsSearch: '', galleries: {} }; @@ -27285,9 +27333,10 @@ speechSynthesis.getVoices(); D.id = groupId; D.inGroup = false; D.ownerDisplayName = ''; - D.announcementDisplayName = ''; D.treeData = []; D.announcement = {}; + D.posts = []; + D.postsFiltered = []; D.instances = []; D.memberRoles = []; if (this.groupDialogLastGallery !== groupId) { @@ -27348,30 +27397,23 @@ speechSynthesis.getVoices(); } } if (D.inGroup) { - API.getGroupAnnouncement({ + API.getAllGroupPosts({ groupId }).then((args2) => { - if (groupId === args2.json.groupId) { - D.announcement = args2.json; - if (D.announcement.id) { - D.announcement.title = - this.replaceBioSymbols( - D.announcement.title - ); - D.announcement.text = - this.replaceBioSymbols( - D.announcement.text - ); + if (groupId === args2.params.groupId) { + for (var post of args2.posts) { + post.title = this.replaceBioSymbols( + post.title + ); + post.text = this.replaceBioSymbols( + post.text + ); } - if (D.announcement && D.announcement.authorId) { - API.getCachedUser({ - userId: D.announcement.authorId - }).then((args3) => { - D.announcementDisplayName = - args3.ref.displayName; - return args3; - }); + if (args2.posts.length > 0) { + D.announcement = args2.posts[0]; } + D.posts = args2.posts; + this.updateGroupPostSearch(); } }); API.getGroupInstances({ @@ -27385,19 +27427,34 @@ speechSynthesis.getVoices(); }); } if (this.$refs.groupDialogTabs.currentName === '0') { - this.groupDialogLastActiveTab = 'Info'; + this.groupDialogLastActiveTab = $t( + 'dialog.group.info.header' + ); } else if (this.$refs.groupDialogTabs.currentName === '1') { - this.groupDialogLastActiveTab = 'Members'; + this.groupDialogLastActiveTab = $t( + 'dialog.group.posts.header' + ); + } else if (this.$refs.groupDialogTabs.currentName === '2') { + this.groupDialogLastActiveTab = $t( + 'dialog.group.members.header' + ); if (this.groupDialogLastMembers !== groupId) { this.groupDialogLastMembers = groupId; this.getGroupDialogGroupMembers(); } - } else if (this.$refs.groupDialogTabs.currentName === '2') { - this.groupDialogLastActiveTab = 'Gallery'; + } else if (this.$refs.groupDialogTabs.currentName === '3') { + this.groupDialogLastActiveTab = $t( + 'dialog.group.gallery.header' + ); if (this.groupDialogLastGallery !== groupId) { this.groupDialogLastGallery = groupId; this.getGroupGalleries(); } + } else if (this.$refs.groupDialogTabs.currentName === '4') { + this.groupDialogLastActiveTab = $t( + 'dialog.group.json.header' + ); + this.refreshGroupDialogTreeData(); } } return args1; @@ -27446,7 +27503,11 @@ speechSynthesis.getVoices(); if (this.groupDialogLastActiveTab === obj.label) { return; } - if (obj.label === $t('dialog.group.members.header')) { + if (obj.label === $t('dialog.group.info.header')) { + // + } else if (obj.label === $t('dialog.group.posts.header')) { + // + } else if (obj.label === $t('dialog.group.members.header')) { if (this.groupDialogLastMembers !== groupId) { this.groupDialogLastMembers = groupId; this.getGroupDialogGroupMembers(); @@ -27466,7 +27527,7 @@ speechSynthesis.getVoices(); var D = this.groupDialog; D.treeData = buildTreeData({ group: D.ref, - announcement: D.announcement, + posts: D.posts, instances: D.instances, members: D.members, galleries: D.galleries @@ -27588,6 +27649,26 @@ speechSynthesis.getVoices(); API.currentUserGroups.delete(groupId); }; + // group posts + + $app.methods.updateGroupPostSearch = function () { + var D = this.groupDialog; + var search = D.postsSearch.toLowerCase(); + D.postsFiltered = D.posts.filter((post) => { + if (search === '') { + return true; + } + if (post.title.toLowerCase().includes(search)) { + return true; + } + if (post.text.toLowerCase().includes(search)) { + return true; + } + return false; + }); + }; + + // group members $app.data.isGroupMembersLoading = false; diff --git a/html/src/index.pug b/html/src/index.pug index 9a84cd7a..9545a9ee 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -481,7 +481,14 @@ html img(v-lazy="group.iconUrl") .detail span.name(v-text="group.name") - span.extra ({{ group.memberCount }}) + span.extra + el-tooltip(v-if="group.isRepresenting" placement="top" :content="$t('dialog.group.members.representing')") + i.el-icon-collection-tag(style="margin-right:5px") + el-tooltip(v-if="group.memberVisibility !== 'visible'" placement="top") + template(#content) + span {{ $t('dialog.group.members.visibility') }} {{ group.memberVisibility }} + i.el-icon-view(style="margin-right:5px") + span ({{ group.memberCount }}) template(v-if="userGroups.mutualGroups.length > 0") span(style="font-weight:bold;font-size:16px") {{ $t('dialog.user.groups.mutual_groups') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ userGroups.mutualGroups.length }} @@ -491,7 +498,14 @@ html img(v-lazy="group.iconUrl") .detail span.name(v-text="group.name") - span.extra ({{ group.memberCount }}) + span.extra + el-tooltip(v-if="group.isRepresenting" placement="top" :content="$t('dialog.group.members.representing')") + i.el-icon-collection-tag(style="margin-right:5px") + el-tooltip(v-if="group.memberVisibility !== 'visible'" placement="top") + template(#content) + span {{ $t('dialog.group.members.visibility') }} {{ group.memberVisibility }} + i.el-icon-view(style="margin-right:5px") + span ({{ group.memberCount }}) template(v-if="userGroups.remainingGroups.length > 0") span(style="font-weight:bold;font-size:16px") {{ $t('dialog.user.groups.groups') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ userGroups.remainingGroups.length }} @@ -501,7 +515,14 @@ html img(v-lazy="group.iconUrl") .detail span.name(v-text="group.name") - span.extra ({{ group.memberCount }}) + span.extra + el-tooltip(v-if="group.isRepresenting" placement="top" :content="$t('dialog.group.members.representing')") + i.el-icon-collection-tag(style="margin-right:5px") + el-tooltip(v-if="group.memberVisibility !== 'visible'" placement="top") + template(#content) + span {{ $t('dialog.group.members.visibility') }} {{ group.memberVisibility }} + i.el-icon-view(style="margin-right:5px") + span ({{ group.memberCount }}) el-tab-pane(:label="$t('dialog.user.worlds.header')") el-button(type="default" :loading="userDialog.isWorldsLoading" @click="refreshUserDialogWorlds()" size="mini" icon="el-icon-refresh" circle) span(style="margin-left:5px") {{ $t('dialog.user.worlds.total_count', { count: userDialog.worlds.length }) }} @@ -1000,12 +1021,20 @@ html pre.extra(style="display:inline-block;vertical-align:top;font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0") {{ groupDialog.announcement.text || '-' }} br .extra(v-if="groupDialog.announcement.id" style="float:right;margin-left:5px") + el-tooltip(v-if="groupDialog.announcement.roleIds.length" placement="top") + template(#content) + span {{ $t('dialog.group.posts.visibility') }} + br + template(v-for="roleId in groupDialog.announcement.roleIds" :key="roleId") + span(v-for="(role, rIndex) in groupDialog.ref.roles" :key="rIndex" v-if="role.id === roleId" v-text="role.name") + span(v-if="groupDialog.announcement.roleIds.indexOf(roleId) < groupDialog.announcement.roleIds.length - 1") ,  + i.el-icon-view(style="margin-right:5px") + display-name(:userid="groupDialog.announcement.authorId" style="margin-right:5px") + span(v-if="groupDialog.announcement.editorId" style="margin-right:5px") ({{ $t('dialog.group.posts.edited_by') }} #[display-name(:userid="groupDialog.announcement.editorId")]) el-tooltip(placement="bottom") template(#content) span {{ groupDialog.announcement.updatedAt | formatDate('long') }} - span(@click="showUserDialog(groupDialog.announcement.authorId)" style="cursor:pointer") - span(v-text="groupDialog.announcementDisplayName" style="margin-right:5px") - timer(:epoch="Date.parse(groupDialog.announcement.updatedAt)") + timer(:epoch="Date.parse(groupDialog.announcement.updatedAt)") .x-friend-item(style="width:100%;cursor:default") .detail span.name {{ $t('dialog.group.info.rules') }} @@ -1065,6 +1094,35 @@ html span {{ permission }} br span {{ role.name }}{{ rIndex < groupDialog.memberRoles.length - 1 ? ', ' : '' }} + el-tab-pane(:label="$t('dialog.group.posts.header')") + template(v-if="groupDialog.visible") + span(style="margin-right:10px") {{ $t('dialog.group.posts.posts_count') }} {{ groupDialog.posts.length }} + el-input(v-model="groupDialog.postsSearch" @input="updateGroupPostSearch" clearable size="mini" :placeholder="$t('dialog.group.posts.search_placeholder')" style="width:89%;margin-bottom:10px") + .x-friend-list + .x-friend-item(v-for="post in groupDialog.postsFiltered" :key="post.id" style="width:100%;cursor:default") + .detail + span(style="display:block" v-text="post.title") + div(v-if="post.imageUrl" style="display:inline-block;margin-right:5px") + el-popover(placement="right" width="500px" trigger="click") + img.x-link(slot="reference" v-lazy="post.imageUrl" style="flex:none;width:60px;height:60px;border-radius:4px;object-fit:cover") + img.x-link(v-lazy="post.imageUrl" style="height:500px" @click="showFullscreenImageDialog(post.imageUrl)") + pre.extra(style="display:inline-block;vertical-align:top;font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0") {{ post.text || '-' }} + br + .extra(v-if="post.authorId" style="float:right;margin-left:5px") + el-tooltip(v-if="post.roleIds.length" placement="top") + template(#content) + span {{ $t('dialog.group.posts.visibility') }} + br + template(v-for="roleId in post.roleIds" :key="roleId") + span(v-for="(role, rIndex) in groupDialog.ref.roles" :key="rIndex" v-if="role.id === roleId" v-text="role.name") + span(v-if="post.roleIds.indexOf(roleId) < post.roleIds.length - 1") ,  + i.el-icon-view(style="margin-right:5px") + display-name(:userid="post.authorId" style="margin-right:5px") + span(v-if="post.editorId" style="margin-right:5px") ({{ $t('dialog.group.posts.edited_by') }} #[display-name(:userid="post.editorId")]) + el-tooltip(placement="bottom") + template(#content) + span {{ post.updatedAt | formatDate('long') }} + timer(:epoch="Date.parse(post.updatedAt)") el-tab-pane(:label="$t('dialog.group.members.header')") template(v-if="groupDialog.visible") span(v-if="hasGroupPermission(groupDialog.ref, 'group-members-viewall')" style="font-weight:bold;font-size:16px") {{ $t('dialog.group.members.all_members') }} @@ -1111,7 +1169,7 @@ html span.name {{ $t('dialog.group.members.load_more') }} el-tab-pane(:label="$t('dialog.group.gallery.header')") el-button(type="default" size="mini" icon="el-icon-refresh" @click="getGroupGalleries" :loading="isGroupGalleryLoading" circle) - el-tabs(type="card" v-loading="isGroupGalleryLoading" ref="groupDialogGallery") + el-tabs(type="card" v-loading="isGroupGalleryLoading" ref="groupDialogGallery" style="margin-top:10px") template(v-for="(gallery, index) in groupDialog.ref.galleries") el-tab-pane span(slot="label") diff --git a/html/src/localization/en/en.json b/html/src/localization/en/en.json index 9b797b24..78c7be8c 100644 --- a/html/src/localization/en/en.json +++ b/html/src/localization/en/en.json @@ -824,6 +824,13 @@ "role_created_at": "Created At:", "role_permissions": "Permissions:" }, + "posts": { + "header": "Posts", + "visibility": "Visibility:", + "edited_by": "Edited by:", + "search_placeholder": "Search", + "posts_count": "Posts: " + }, "members": { "header": "Members", "all_members": "All Members",