diff --git a/.eslintrc.json b/.eslintrc.json index 76959199..d8b8f81e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "extends": ["eslint:all", "plugin:vue/recommended", "prettier"], + "extends": ["eslint:recommended", "plugin:vue/recommended", "prettier"], "env": { "browser": true, "commonjs": true, @@ -36,28 +36,7 @@ "AssetBundleManager": "readonly" }, "rules": { - "arrow-body-style": 0, - "block-scoped-var": 0, - "camelcase": 0, - "capitalized-comments": 0, - "class-methods-use-this": 0, - "complexity": 0, - "default-case": 0, - "func-names": 0, - "func-style": 0, - "guard-for-in": 0, - "id-length": 0, - "line-comment-position": 0, - "max-depth": 0, - "max-lines": 0, - "max-lines-per-function": 0, - "max-params": 0, - "max-statements": 0, - "multiline-comment-style": 0, - "new-cap": 0, - "no-await-in-loop": 0, "no-console": 0, - "no-continue": 0, "no-control-regex": 0, "no-empty": [ "error", @@ -65,29 +44,9 @@ "allowEmptyCatch": true } ], - "no-inline-comments": 0, - "no-invalid-this": 0, + "no-var": "warn", + "prefer-const": "warn", "no-loop-func": 0, - "no-magic-numbers": 0, - "no-negated-condition": 0, - "no-plusplus": 0, - "no-redeclare": 0, - "no-ternary": 0, - "no-throw-literal": 0, - "no-underscore-dangle": 0, - "no-var": 0, - "no-void": 0, - "no-warning-comments": 0, - "one-var": 0, - "prefer-arrow-callback": 0, - "prefer-const": 0, - "prefer-destructuring": 0, - "prefer-named-capture-group": 0, - "require-unicode-regexp": 0, - "sort-imports": 0, - "sort-keys": 0, - "sort-vars": 0, - "strict": 0, "vars-on-top": 0, "object-curly-spacing": ["error", "always"], "require-atomic-updates": 0 diff --git a/package-lock.json b/package-lock.json index 35aa9d5c..2c45192d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,7 @@ "vue-data-tables": "^3.4.5", "vue-demi": "^0.14.10", "vue-i18n": "^8.28.2", + "vue-i18n-bridge": "^9.14.1", "vue-lazyload": "^1.3.4", "vue-loader": "^15.11.1", "vue-markdown": "^2.2.4", @@ -1382,6 +1383,70 @@ "integrity": "sha512-B6kpvqeD0ukTR7sydGKpktvO3VhZkOwQxAdLLGPdSHxQxREa2+sH6B9ODop6quPGjhmsZkJ/hL01rQ8At5xDew==", "dev": true }, + "node_modules/@intlify/core-base": { + "version": "9.14.1", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.1.tgz", + "integrity": "sha512-rG5/hlNW6Qfve41go37szEf0mVLcfhYuOu83JcY0jZKasnwsrcZYYWDzebCcuO5I/6Sy1JFWo9p+nvkQS1Dy+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@intlify/message-compiler": "9.14.1", + "@intlify/shared": "9.14.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "9.14.1", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.14.1.tgz", + "integrity": "sha512-MY8hwukJBnXvGAncVKlHsqKDQ5ZcQx4peqEmI8wBUTXn4pezrtTGYXNoz81cLyEEHB+L/zlKWVBSh5TiX4gYoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@intlify/shared": "9.14.1", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/shared": { + "version": "9.14.1", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.14.1.tgz", + "integrity": "sha512-XjHu6PEQup9MnP1x0W9y0nXXfq9jFftAYSfV11hryjtH4XqXP8HrzMvXI+ZVifF+jZLszaTzIhvukllplxTQTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/vue-devtools": { + "version": "9.14.1", + "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.14.1.tgz", + "integrity": "sha512-twkyipsHAVXesM0edbQ8oaePUaQdgjlftX6udQvNsgItXf3qK+gLM6NFEduvoruexOWi7iipLXL5Luk7B9yf9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@intlify/core-base": "9.14.1", + "@intlify/shared": "9.14.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -2289,6 +2354,13 @@ "dev": true, "license": "ISC" }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "dev": true, + "license": "MIT" + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -9695,6 +9767,34 @@ "integrity": "sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA==", "dev": true }, + "node_modules/vue-i18n-bridge": { + "version": "9.14.1", + "resolved": "https://registry.npmjs.org/vue-i18n-bridge/-/vue-i18n-bridge-9.14.1.tgz", + "integrity": "sha512-KmCO/Pk5RwqtHqT1k/njhaGuSQmO6RKjtf4QK7aQVoUKlWBkRBwI4PWQRUjne09E9txBncw6dSZzRdiVew/oFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@intlify/core-base": "9.14.1", + "@intlify/shared": "9.14.1", + "@intlify/vue-devtools": "9.14.1", + "@vue/devtools-api": "^6.5.0", + "vue-demi": "^0.14.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/vue-lazyload": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.4.tgz", diff --git a/package.json b/package.json index be453187..2fd7a0af 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "vue-data-tables": "^3.4.5", "vue-demi": "^0.14.10", "vue-i18n": "^8.28.2", + "vue-i18n-bridge": "^9.14.1", "vue-lazyload": "^1.3.4", "vue-loader": "^15.11.1", "vue-markdown": "^2.2.4", diff --git a/src/app.js b/src/app.js index 3f962e6f..3ae5b47b 100644 --- a/src/app.js +++ b/src/app.js @@ -14,6 +14,7 @@ import Noty from 'noty'; import Vue from 'vue'; import VueLazyload from 'vue-lazyload'; import VueI18n from 'vue-i18n'; +import { createI18n } from 'vue-i18n-bridge'; import { DataTables } from 'vue-data-tables'; import ElementUI from 'element-ui'; import dayjs from 'dayjs'; @@ -49,7 +50,8 @@ import { inviteMessagesRequest, miscRequest, imageRequest, - vrcPlusImageRequest + vrcPlusImageRequest, + groupRequest } from './classes/request'; // tabs @@ -75,6 +77,8 @@ import PreviousInstancesUserDialog from './views/dialogs/previousInstances/Previ import FavoriteDialog from './views/dialogs/favoritesDialog/FavoriteDialog.vue'; import ExportFriendsListDialog from './views/dialogs/favoritesDialog/ExportFriendsListDialog.vue'; import ExportAvatarsListDialog from './views/dialogs/favoritesDialog/ExportAvatarsListDialog.vue'; +import GroupDialog from './views/dialogs/groupDialog/GroupDialog.vue'; +import InviteGroupDialog from './views/dialogs/groupDialog/InviteGroupDialog.vue'; // main app classes import _sharedFeed from './classes/sharedFeed.js'; @@ -136,16 +140,24 @@ console.log(`isLinux: ${LINUX}`); } // #region | localization - Vue.use(VueI18n); - const i18n = new VueI18n({ - locale: 'en', - fallbackLocale: 'en', - messages: localizedStrings, - silentTranslationWarn: true - }); - const $t = i18n.t.bind(i18n); + Vue.use(VueI18n, { bridge: true }); + const i18n = createI18n( + { + locale: 'en', + fallbackLocale: 'en', + messages: localizedStrings, + legacy: false, + globalInjection: true, + missingWarn: false, + warnHtmlMessage: false, + fallbackWarn: false + }, + VueI18n + ); + const $t = i18n.global.t; + Vue.use(i18n); Vue.use(ElementUI, { - i18n: (key, value) => i18n.t(key, value) + i18n: (key, value) => i18n.global.t(key, value) }); // #endregion @@ -225,6 +237,9 @@ console.log(`isLinux: ${LINUX}`); PreviousInstancesUserDialog, // - world WorldDialog, + // - group + GroupDialog, + InviteGroupDialog, // - favorites FriendImportDialog, WorldImportDialog, @@ -248,7 +263,6 @@ console.log(`isLinux: ${LINUX}`); userImageFull: this.userImageFull, showFullscreenImageDialog: this.showFullscreenImageDialog, statusClass: this.statusClass, - getFaviconUrl: this.getFaviconUrl, openExternalLink: this.openExternalLink, beforeDialogClose: this.beforeDialogClose, dialogMouseDown: this.dialogMouseDown, @@ -260,7 +274,10 @@ console.log(`isLinux: ${LINUX}`); showInviteDialog: this.showInviteDialog, showLaunchDialog: this.showLaunchDialog, showFavoriteDialog: this.showFavoriteDialog, - displayPreviousImages: this.displayPreviousImages + displayPreviousImages: this.displayPreviousImages, + languageClass: this.languageClass, + showGroupDialog: this.showGroupDialog, + showGallerySelectDialog: this.showGallerySelectDialog }; }, el: '#root', @@ -287,15 +304,9 @@ console.log(`isLinux: ${LINUX}`); this.enableAppLauncher, this.enableAppLauncherAutoClose ); - API.$on('SHOW_USER_DIALOG', (userId) => - this.showUserDialog(userId) - ); API.$on('SHOW_WORLD_DIALOG_SHORTNAME', (tag) => this.verifyShortName('', tag) ); - API.$on('SHOW_GROUP_DIALOG', (groupId) => - this.showGroupDialog(groupId) - ); this.updateLoop(); this.getGameLogTable(); this.refreshCustomCss(); @@ -4169,13 +4180,6 @@ console.log(`isLinux: ${LINUX}`); $app.data.gameLogTable.pageSize = $app.data.tablePageSize; $app.data.feedTable.pageSize = $app.data.tablePageSize; - $app.data.groupMemberModerationTable.pageSize = $app.data.tablePageSize; - $app.data.groupBansModerationTable.pageSize = $app.data.tablePageSize; - $app.data.groupLogsModerationTable.pageSize = $app.data.tablePageSize; - $app.data.groupInvitesModerationTable.pageSize = $app.data.tablePageSize; - $app.data.groupJoinRequestsModerationTable.pageSize = - $app.data.tablePageSize; - $app.data.groupBlockedModerationTable.pageSize = $app.data.tablePageSize; $app.data.dontLogMeOut = false; @@ -5559,11 +5563,22 @@ console.log(`isLinux: ${LINUX}`); } } this.isSearchGroupLoading = true; - await API.groupSearch(params) + await groupRequest + .groupSearch(params) .finally(() => { this.isSearchGroupLoading = false; }) .then((args) => { + // API.$on('GROUP:SEARCH', function (args) { + for (const json of args.json) { + API.$emit('GROUP', { + json, + params: { + groupId: json.id + } + }); + } + // }); var map = new Map(); for (var json of args.json) { var ref = API.cachedGroups.get(json.id); @@ -8263,8 +8278,18 @@ console.log(`isLinux: ${LINUX}`); }; $app.methods.showGroupDialogShortCode = function (shortCode) { - API.groupStrictsearch({ query: shortCode }).then((args) => { - for (var group of args.json) { + groupRequest.groupStrictsearch({ query: shortCode }).then((args) => { + for (const group of args.json) { + // API.$on('GROUP:STRICTSEARCH', function (args) { + // for (var json of args.json) { + API.$emit('GROUP', { + group, + params: { + groupId: group.id + } + }); + // } + // }); if (`${group.shortCode}.${group.discriminator}` === shortCode) { this.showGroupDialog(group.id); } @@ -8461,15 +8486,6 @@ console.log(`isLinux: ${LINUX}`); await this.sortCurrentUserGroups(); }; - $app.methods.getFaviconUrl = function (resource) { - try { - var url = new URL(resource); - return `https://icons.duckduckgo.com/ip2/${url.host}.ico`; - } catch (err) { - return ''; - } - }; - API.$on('LOGOUT', function () { $app.userDialog.visible = false; }); @@ -8912,14 +8928,18 @@ console.log(`isLinux: ${LINUX}`); } }); } - API.getRepresentedGroup({ userId }).then((args1) => { - D.representedGroup = args1.json; - D.representedGroup.$thumbnailUrl = - this.getSmallThumbnailUrl(args1.json.iconUrl); - if (!args1.json || !args1.json.isRepresenting) { - D.isRepresentedGroupLoading = false; - } - }); + groupRequest + .getRepresentedGroup({ userId }) + .then((args1) => { + D.representedGroup = args1.json; + D.representedGroup.$thumbnailUrl = + this.getSmallThumbnailUrl( + args1.json.iconUrl + ); + if (!args1.json || !args1.json.isRepresenting) { + D.isRepresentedGroupLoading = false; + } + }); D.loading = false; }); } @@ -10943,7 +10963,7 @@ console.log(`isLinux: ${LINUX}`); this.showSetAvatarTagsDialog(D.id); break; case 'Download Unity Package': - $utils.openExternalLink( + this.openExternalLink( this.replaceVrcPackageUrl( this.avatarDialog.ref.unityPackageUrl ) @@ -11639,7 +11659,7 @@ console.log(`isLinux: ${LINUX}`); if ( D.ageGate && type === 'group' && - this.hasGroupPermission( + $utils.hasGroupPermission( D.groupRef, 'group-instance-age-gated-create' ) @@ -12196,22 +12216,6 @@ console.log(`isLinux: ${LINUX}`); this.copyToClipboard(displayName); }; - $app.methods.copyGroupId = function (groupId) { - this.$message({ - message: 'Group ID copied to clipboard', - type: 'success' - }); - this.copyToClipboard(groupId); - }; - - $app.methods.copyGroupUrl = function (groupUrl) { - this.$message({ - message: 'Group URL copied to clipboard', - type: 'success' - }); - this.copyToClipboard(groupUrl); - }; - $app.methods.copyImageUrl = function (imageUrl) { this.$message({ message: 'ImageUrl copied to clipboard', @@ -15134,6 +15138,7 @@ console.log(`isLinux: ${LINUX}`); return style; }; + // TODO: launch, invite, refresh, etc. buttons, better to split into one component $app.methods.refreshInstancePlayerCount = function (instance) { var L = $utils.parseLocation(instance); if (L.isRealInstance) { @@ -15161,7 +15166,7 @@ console.log(`isLinux: ${LINUX}`); mutualGroups: [], remainingGroups: [] }; - var args = await API.getGroups({ userId }); + var args = await groupRequest.getGroups({ userId }); if (userId !== this.userDialog.id) { this.userDialog.isGroupsLoading = false; return; @@ -18649,6 +18654,8 @@ console.log(`isLinux: ${LINUX}`); } }; + // use in avatar, user, group dialog + // TODO: better in utils $app.methods.downloadAndSaveJson = function (fileName, data) { if (!fileName || !data) { return; @@ -18752,6 +18759,9 @@ console.log(`isLinux: ${LINUX}`); }; }; + $app.data.groupDialogSortingOptions = {}; + $app.data.groupDialogFilterOptions = {}; + $app.methods.applyGroupDialogSortingStrings = function () { this.groupDialogSortingOptions = { joinedAtDesc: { @@ -19299,7 +19309,6 @@ console.log(`isLinux: ${LINUX}`); hideTooltips: this.hideTooltips, randomUserColours: this.randomUserColours, sortStatus: this.sortStatus, - languageClass: this.languageClass, confirmDeleteFriend: this.confirmDeleteFriend, friendsListSearch: this.friendsListSearch, stringComparer: this.stringComparer @@ -19626,6 +19635,54 @@ console.log(`isLinux: ${LINUX}`); }; }; + $app.computed.groupDialogBind = function () { + return { + 'group-dialog': this.groupDialog, + 'hide-tooltips': this.hideTooltips, + 'last-location': this.lastLocation, + 'update-instance-info': this.updateInstanceInfo, + 'group-dialog-sorting-options': this.groupDialogSortingOptions, + 'group-dialog-filter-options': this.groupDialogFilterOptions, + 'is-group-gallery-loading': this.isGroupGalleryLoading, + 'gallery-select-dialog': this.gallerySelectDialog, + 'random-user-colours': this.randomUserColours + }; + }; + + $app.computed.groupDialogEvent = function () { + return { + 'refresh-instance-player-count': this.refreshInstancePlayerCount, + 'update-group-post-search': this.updateGroupPostSearch, + 'download-and-save-json': this.downloadAndSaveJson, + 'group-dialog-command': this.groupDialogCommand, + 'get-group-dialog-group': this.getGroupDialogGroup, + 'clear-image-gallery-select': this.clearImageGallerySelect, + 'update:gallery-select-dialog': (val) => + (this.gallerySelectDialog = val), + 'update:group-dialog': (val) => { + this.groupDialog = val; + } + }; + }; + + $app.computed.inviteGroupDialogBind = function () { + return { + 'dialog-data': this.inviteGroupDialog, + 'vip-friends': this.vipFriends, + 'online-friends': this.onlineFriends, + 'offline-friends': this.offlineFriends, + 'active-friends': this.activeFriends + }; + }; + + $app.computed.inviteGroupDialogEvent = function () { + return { + 'update:dialog-data': (val) => { + this.inviteGroupDialog = val; + } + }; + }; + // #endregion // #region | Electron diff --git a/src/app.pug b/src/app.pug index 623e2e7c..e7bbf7c9 100644 --- a/src/app.pug +++ b/src/app.pug @@ -80,9 +80,6 @@ doctype html include ./mixins/dialogs/avatarDialog.pug +avatarDialog - include ./mixins/dialogs/groupDialog.pug - +groupDialog - include ./mixins/dialogs/images.pug +images @@ -92,9 +89,6 @@ doctype html include ./mixins/dialogs/openSourceSoftwareNotice.pug +openSourceSoftwareNotice - include ./mixins/dialogs/groups.pug - +groups - include ./mixins/dialogs/currentUser.pug +currentUser @@ -144,4 +138,9 @@ doctype html //- world world-dialog(v-bind='worldDialogBind' v-on='worldDialogEvent') + //- group + GroupDialog(v-bind='groupDialogBind' v-on='groupDialogEvent') + + InviteGroupDialog(v-bind='inviteGroupDialogBind' v-on='inviteGroupDialogEvent') + //- el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="templateDialog" :visible.sync="templateDialog.visible" :title="$t('dialog.template_dialog.header')" width="450px") diff --git a/src/app.scss b/src/app.scss index 97f88b89..ed786156 100644 --- a/src/app.scss +++ b/src/app.scss @@ -560,7 +560,6 @@ img.friends-list-avatar { .x-dialog > .el-dialog { max-width: 100%; - margin-bottom: 10px; } .x-user-dialog > .el-dialog > .el-dialog__header, diff --git a/src/classes/groups.js b/src/classes/groups.js index 9c2fe8a4..af451309 100644 --- a/src/classes/groups.js +++ b/src/classes/groups.js @@ -1,7 +1,12 @@ import * as workerTimers from 'worker-timers'; import configRepository from '../repository/config.js'; -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; -import { userRequest, worldRequest, instanceRequest } from './request'; +import { baseClass, $app, API, $t } from './baseClass.js'; +import { + userRequest, + worldRequest, + instanceRequest, + groupRequest +} from './request'; export default class extends baseClass { constructor(_app, _API, _t) { @@ -12,25 +17,6 @@ export default class extends baseClass { API.cachedGroups = new Map(); API.currentUserGroups = new Map(); - /** - * @param {{ groupId: string }} params - */ - API.getGroup = function (params) { - return this.call(`groups/${params.groupId}`, { - method: 'GET', - params: { - includeRoles: params.includeRoles || false - } - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP', args); - return args; - }); - }; - API.$on('GROUP', function (args) { args.ref = this.applyGroup(args.json); }); @@ -45,23 +31,6 @@ export default class extends baseClass { D.ref = ref; }); - /** - * @param {{ userId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.getRepresentedGroup = function (params) { - return this.call(`users/${params.userId}/groups/represented`, { - method: 'GET' - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:REPRESENTED', args); - return args; - }); - }; - API.$on('GROUP:REPRESENTED', function (args) { var json = args.json; if (!json.groupId) { @@ -79,23 +48,6 @@ export default class extends baseClass { }); }); - /** - * @param {{ userId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.getGroups = function (params) { - return this.call(`users/${params.userId}/groups`, { - method: 'GET' - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:LIST', args); - return args; - }); - }; - API.$on('GROUP:LIST', function (args) { for (var json of args.json) { json.$memberId = json.id; @@ -110,194 +62,6 @@ export default class extends baseClass { } }); - /** - * @param {{ groupId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.joinGroup = function (params) { - return this.call(`groups/${params.groupId}/join`, { - method: 'POST' - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:JOIN', args); - return args; - }); - }; - - API.$on('GROUP:JOIN', function (args) { - var json = { - $memberId: args.json.id, - id: args.json.groupId, - membershipStatus: args.json.membershipStatus, - myMember: { - isRepresenting: args.json.isRepresenting, - id: args.json.id, - roleIds: args.json.roleIds, - joinedAt: args.json.joinedAt, - membershipStatus: args.json.membershipStatus, - visibility: args.json.visibility, - isSubscribedToAnnouncements: - args.json.isSubscribedToAnnouncements - } - }; - var groupId = json.id; - this.$emit('GROUP', { - json, - params: { - groupId, - userId: args.params.userId - } - }); - if ($app.groupDialog.visible && $app.groupDialog.id === groupId) { - $app.groupDialog.inGroup = json.membershipStatus === 'member'; - $app.getGroupDialogGroup(groupId); - } - }); - - /** - * @param {{ groupId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.leaveGroup = function (params) { - return this.call(`groups/${params.groupId}/leave`, { - method: 'POST' - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:LEAVE', args); - return args; - }); - }; - - API.$on('GROUP:LEAVE', function (args) { - var groupId = args.params.groupId; - if ($app.groupDialog.visible && $app.groupDialog.id === groupId) { - $app.groupDialog.inGroup = false; - $app.getGroupDialogGroup(groupId); - } - if ( - $app.userDialog.visible && - $app.userDialog.id === this.currentUser.id && - $app.userDialog.representedGroup.id === groupId - ) { - $app.getCurrentUserRepresentedGroup(); - } - }); - - /** - * @param {{ groupId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.cancelGroupRequest = function (params) { - return this.call(`groups/${params.groupId}/requests`, { - method: 'DELETE' - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:CANCELJOINREQUEST', args); - return args; - }); - }; - - API.$on('GROUP:CANCELJOINREQUEST', function (args) { - var groupId = args.params.groupId; - if ($app.groupDialog.visible && $app.groupDialog.id === groupId) { - $app.getGroupDialogGroup(groupId); - } - }); - - /* - groupId: string, - params: { - isRepresenting: bool - } - */ - API.setGroupRepresentation = function (groupId, params) { - return this.call(`groups/${groupId}/representation`, { - method: 'PUT', - params - }).then((json) => { - var args = { - json, - groupId, - params - }; - this.$emit('GROUP:SETREPRESENTATION', args); - return args; - }); - }; - - API.$on('GROUP:SETREPRESENTATION', function (args) { - if ( - $app.groupDialog.visible && - $app.groupDialog.id === args.groupId - ) { - $app.groupDialog.ref.isRepresenting = - args.params.isRepresenting; - } - }); - - /** - * @param {{ query: string }} params - * @return { Promise<{json: any, params}> } - */ - API.groupStrictsearch = function (params) { - return this.call(`groups/strictsearch`, { - method: 'GET', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:STRICTSEARCH', args); - return args; - }); - }; - - API.$on('GROUP:STRICTSEARCH', function (args) { - for (var json of args.json) { - this.$emit('GROUP', { - json, - params: { - groupId: json.id - } - }); - } - }); - - /* - userId: string, - groupId: string, - params: { - visibility: string, - isSubscribedToAnnouncements: bool, - managerNotes: string - } - */ - API.setGroupMemberProps = function (userId, groupId, params) { - return this.call(`groups/${groupId}/members/${userId}`, { - method: 'PUT', - params - }).then((json) => { - var args = { - json, - userId, - groupId, - params - }; - this.$emit('GROUP:MEMBER:PROPS', args); - return args; - }); - }; - API.$on('GROUP:MEMBER:PROPS', function (args) { if (args.userId !== this.currentUser.id) { return; @@ -348,107 +112,20 @@ export default class extends baseClass { } } } - if ( - $app.groupMemberModeration.visible && - $app.groupMemberModeration.id === args.json.groupId - ) { - // force redraw table - $app.groupMembersSearch(); - } + + // The 'GROUP:MEMBER:PROPS' event is triggered by the setGroupVisibility, setGroupSubscription, or groupMembersSaveNote. + // The first two methods originate from the Group Dialog (visibility/Subscription); + // Group Member Moderation Dialog is necessarily not visible then. + + // if ( + // $app.groupMemberModeration.visible && + // $app.groupMemberModeration.id === args.json.groupId + // ) { + // // force redraw table + // $app.groupMembersSearch(); + // } }); - /** - * @param {{ - userId: string, - groupId: string, - roleId: string - }} params - * @return { Promise<{json: any, params}> } - */ - API.addGroupMemberRole = function (params) { - return this.call( - `groups/${params.groupId}/members/${params.userId}/roles/${params.roleId}`, - { - method: 'PUT' - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:MEMBER:ROLE:CHANGE', args); - return args; - }); - }; - - /** - * @param {{ - userId: string, - groupId: string, - roleId: string - }} params - * @return { Promise<{json: any, params}> } - */ - API.removeGroupMemberRole = function (params) { - return this.call( - `groups/${params.groupId}/members/${params.userId}/roles/${params.roleId}`, - { - method: 'DELETE' - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:MEMBER:ROLE:CHANGE', args); - return args; - }); - }; - - API.$on('GROUP:MEMBER:ROLE:CHANGE', function (args) { - if ($app.groupDialog.id === args.params.groupId) { - for (var i = 0; i < $app.groupDialog.members.length; ++i) { - var member = $app.groupDialog.members[i]; - if (member.userId === args.params.userId) { - member.roleIds = args.json; - break; - } - } - for ( - var i = 0; - i < $app.groupDialog.memberSearchResults.length; - ++i - ) { - var member = $app.groupDialog.memberSearchResults[i]; - if (member.userId === args.params.userId) { - member.roleIds = args.json; - break; - } - } - } - - if ( - $app.groupMemberModeration.visible && - $app.groupMemberModeration.id === args.params.groupId - ) { - // force redraw table - $app.groupMembersSearch(); - } - }); - - API.getGroupPermissions = function (params) { - return this.call(`users/${params.userId}/groups/permissions`, { - method: 'GET' - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:PERMISSIONS', args); - return args; - }); - }; - API.$on('GROUP:PERMISSIONS', function (args) { if (args.params.userId !== this.currentUser.id) { return; @@ -463,45 +140,6 @@ export default class extends baseClass { } }); - // /** - // * @param {{ groupId: string }} params - // * @return { Promise<{json: any, params}> } - // */ - // 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; - // }); - // }; - - /** - * @param {{ - groupId: string, - n: number, - offset: number - }} params - * @return { Promise<{json: any, params}> } - */ - API.getGroupPosts = function (params) { - return this.call(`groups/${params.groupId}/posts`, { - method: 'GET', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:POSTS', args); - return args; - }); - }; - /** * @param {{ groupId: string }} params * @return { Promise<{json: any, params}> } @@ -512,7 +150,7 @@ export default class extends baseClass { var n = 100; var total = 0; do { - var args = await this.getGroupPosts({ + var args = await groupRequest.getGroupPosts({ groupId: params.groupId, n, offset @@ -573,127 +211,6 @@ export default class extends baseClass { $app.updateGroupPostSearch(); }); - API.$on('GROUP:POST:DELETE', function (args) { - var D = $app.groupDialog; - if (D.id !== args.params.groupId) { - return; - } - - var postId = args.params.postId; - // remove existing post - for (var post of D.posts) { - if (post.id === postId) { - $app.removeFromArray(D.posts, post); - break; - } - } - // remove/update announcement - if (postId === D.announcement.id) { - if (D.posts.length > 0) { - D.announcement = D.posts[0]; - } else { - D.announcement = {}; - } - } - $app.updateGroupPostSearch(); - }); - - /** - * @param {{ groupId: string, postId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.deleteGroupPost = function (params) { - return this.call( - `groups/${params.groupId}/posts/${params.postId}`, - { - method: 'DELETE' - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:POST:DELETE', args); - return args; - }); - }; - - API.editGroupPost = function (params) { - return this.call( - `groups/${params.groupId}/posts/${params.postId}`, - { - method: 'PUT', - params - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:POST', args); - return args; - }); - }; - - API.createGroupPost = function (params) { - return this.call(`groups/${params.groupId}/posts`, { - method: 'POST', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:POST', args); - return args; - }); - }; - - /** - * @param {{ - groupId: string, - userId: string - }} params - * @return { Promise<{json: any, params}> } - */ - API.getGroupMember = function (params) { - return this.call( - `groups/${params.groupId}/members/${params.userId}`, - { - method: 'GET' - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:MEMBER', args); - return args; - }); - }; - - /** - * @param {{ - groupId: string, - n: number, - offset: number - }} params - * @return { Promise<{json: any, params}> } - */ - API.getGroupMembers = function (params) { - return this.call(`groups/${params.groupId}/members`, { - method: 'GET', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:MEMBERS', args); - return args; - }); - }; - API.$on('GROUP:MEMBERS', function (args) { for (var json of args.json) { this.$emit('GROUP:MEMBER', { @@ -709,515 +226,6 @@ export default class extends baseClass { args.ref = this.applyGroupMember(args.json); }); - /** - * @param {{ - groupId: string, - query: string, - n: number, - offset: number - }} params - * @return { Promise<{json: any, params}> } - */ - API.getGroupMembersSearch = function (params) { - return this.call(`groups/${params.groupId}/members/search`, { - method: 'GET', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:MEMBERS:SEARCH', args); - return args; - }); - }; - - API.$on('GROUP:MEMBERS:SEARCH', function (args) { - for (var json of args.json.results) { - this.$emit('GROUP:MEMBER', { - json, - params: { - groupId: args.params.groupId - } - }); - } - }); - - /** - * @param {{ - groupId: string - * }} params - * @return { Promise<{json: any, params}> } - */ - API.blockGroup = function (params) { - return this.call(`groups/${params.groupId}/block`, { - method: 'POST' - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:BLOCK', args); - return args; - }); - }; - - /** - * @param {{ - groupId: string, - userId: string - * }} params - * @return { Promise<{json: any, params}> } - */ - API.unblockGroup = function (params) { - return this.call( - `groups/${params.groupId}/members/${params.userId}`, - { - method: 'DELETE' - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:UNBLOCK', args); - return args; - }); - }; - - API.$on('GROUP:BLOCK', function (args) { - if ( - $app.groupDialog.visible && - $app.groupDialog.id === args.params.groupId - ) { - $app.showGroupDialog(args.params.groupId); - } - }); - - API.$on('GROUP:UNBLOCK', function (args) { - if ( - $app.groupDialog.visible && - $app.groupDialog.id === args.params.groupId - ) { - $app.showGroupDialog(args.params.groupId); - } - }); - - /** - * @param {{ - groupId: string, - userId: string - * }} params - * @return { Promise<{json: any, params}> } - */ - API.sendGroupInvite = function (params) { - return this.call(`groups/${params.groupId}/invites`, { - method: 'POST', - params: { - userId: params.userId - } - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:INVITE', args); - return args; - }); - }; - - /** - * @param {{ - groupId: string, - userId: string - }} params - * @return { Promise<{json: any, params}> } - */ - API.kickGroupMember = function (params) { - return this.call( - `groups/${params.groupId}/members/${params.userId}`, - { - method: 'DELETE' - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:MEMBER:KICK', args); - return args; - }); - }; - - /** - * @param {{ groupId: string, userId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.banGroupMember = function (params) { - return this.call(`groups/${params.groupId}/bans`, { - method: 'POST', - params: { - userId: params.userId - } - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:MEMBER:BAN', args); - return args; - }); - }; - - /** - * @param {{ groupId: string, userId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.unbanGroupMember = function (params) { - return this.call(`groups/${params.groupId}/bans/${params.userId}`, { - method: 'DELETE' - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:MEMBER:UNBAN', args); - return args; - }); - }; - - API.deleteSentGroupInvite = function (params) { - return this.call( - `groups/${params.groupId}/invites/${params.userId}`, - { - method: 'DELETE' - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:INVITE:DELETE', args); - return args; - }); - }; - - API.deleteBlockedGroupRequest = function (params) { - return this.call( - `groups/${params.groupId}/members/${params.userId}`, - { - method: 'DELETE' - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:BLOCKED:DELETE', args); - return args; - }); - }; - - API.acceptGroupInviteRequest = function (params) { - return this.call( - `groups/${params.groupId}/requests/${params.userId}`, - { - method: 'PUT', - params: { - action: 'accept' - } - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:INVITE:ACCEPT', args); - return args; - }); - }; - - API.rejectGroupInviteRequest = function (params) { - return this.call( - `groups/${params.groupId}/requests/${params.userId}`, - { - method: 'PUT', - params: { - action: 'reject' - } - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:INVITE:REJECT', args); - return args; - }); - }; - - API.blockGroupInviteRequest = function (params) { - return this.call( - `groups/${params.groupId}/requests/${params.userId}`, - { - method: 'PUT', - params: { - action: 'reject', - block: true - } - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:INVITE:BLOCK', args); - return args; - }); - }; - - API.getGroupBans = function (params) { - return this.call(`groups/${params.groupId}/bans`, { - method: 'GET', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:BANS', args); - return args; - }); - }; - - API.$on('GROUP:BANS', function (args) { - if ($app.groupMemberModeration.id !== args.params.groupId) { - return; - } - - for (var json of args.json) { - var ref = this.applyGroupMember(json); - $app.groupBansModerationTable.data.push(ref); - } - }); - - /** - * @param {{ groupId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.getGroupAuditLogTypes = function (params) { - return this.call(`groups/${params.groupId}/auditLogTypes`, { - method: 'GET' - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:AUDITLOGTYPES', args); - return args; - }); - }; - - API.$on('GROUP:AUDITLOGTYPES', function (args) { - if ($app.groupMemberModeration.id !== args.params.groupId) { - return; - } - - $app.groupMemberModeration.auditLogTypes = args.json; - }); - - /** - * @param {{ groupId: string, eventTypes: array }} params - * @return { Promise<{json: any, params}> } - */ - API.getGroupLogs = function (params) { - return this.call(`groups/${params.groupId}/auditLogs`, { - method: 'GET', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:LOGS', args); - return args; - }); - }; - - API.$on('GROUP:LOGS', function (args) { - if ($app.groupMemberModeration.id !== args.params.groupId) { - return; - } - - for (var json of args.json.results) { - const existsInData = $app.groupLogsModerationTable.data.some( - (dataItem) => dataItem.id === json.id - ); - if (!existsInData) { - $app.groupLogsModerationTable.data.push(json); - } - } - }); - - /** - * @param {{ groupId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.getGroupInvites = function (params) { - return this.call(`groups/${params.groupId}/invites`, { - method: 'GET', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:INVITES', args); - return args; - }); - }; - - API.$on('GROUP:INVITES', function (args) { - if ($app.groupMemberModeration.id !== args.params.groupId) { - return; - } - - for (var json of args.json) { - var ref = this.applyGroupMember(json); - $app.groupInvitesModerationTable.data.push(ref); - } - }); - - /** - * @param {{ groupId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.getGroupJoinRequests = function (params) { - return this.call(`groups/${params.groupId}/requests`, { - method: 'GET', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:JOINREQUESTS', args); - return args; - }); - }; - - API.$on('GROUP:JOINREQUESTS', function (args) { - if ($app.groupMemberModeration.id !== args.params.groupId) { - return; - } - - if (!args.params.blocked) { - for (var json of args.json) { - var ref = this.applyGroupMember(json); - $app.groupJoinRequestsModerationTable.data.push(ref); - } - } else { - for (var json of args.json) { - var ref = this.applyGroupMember(json); - $app.groupBlockedModerationTable.data.push(ref); - } - } - }); - - /** - * @param {{ groupId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.getGroupInstances = function (params) { - return this.call( - `users/${this.currentUser.id}/instances/groups/${params.groupId}`, - { - method: 'GET' - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:INSTANCES', args); - return args; - }); - }; - - API.$on('GROUP:INSTANCES', function (args) { - if ($app.groupDialog.id === args.params.groupId) { - $app.applyGroupDialogInstances(args.json.instances); - } - }); - - API.$on('GROUP:INSTANCES', function (args) { - for (var json of args.json.instances) { - this.$emit('INSTANCE', { - json, - params: { - fetchedAt: args.json.fetchedAt - } - }); - worldRequest - .getCachedWorld({ - worldId: json.world.id - }) - .then((args1) => { - json.world = args1.ref; - return args1; - }); - // get queue size etc - instanceRequest.getInstance({ - worldId: json.worldId, - instanceId: json.instanceId - }); - } - }); - - /** - * @param {{ groupId: string }} params - * @return { Promise<{json: any, params}> } - */ - - API.getGroupRoles = function (params) { - return this.call(`groups/${params.groupId}/roles`, { - method: 'GET', - params - }).then((json) => { - var args = { - json, - params - }; - // useless code? - // this.$emit('GROUP:ROLES', args); - return args; - }); - }; - - API.getRequestedGroups = function () { - return this.call(`users/${this.currentUser.id}/groups/requested`, { - method: 'GET' - }).then((json) => { - var args = { - json - }; - this.$emit('GROUP:REQUESTED', args); - return args; - }); - }; - - API.getUsersGroupInstances = function () { - return this.call(`users/${this.currentUser.id}/instances/groups`, { - method: 'GET' - }).then((json) => { - var args = { - json - }; - this.$emit('GROUP:USER:INSTANCES', args); - return args; - }); - }; - API.$on('GROUP:USER:INSTANCES', function (args) { $app.groupInstances = []; for (const json of args.json.instances) { @@ -1234,7 +242,7 @@ export default class extends baseClass { const ref = this.cachedGroups.get(json.ownerId); if (typeof ref === 'undefined') { if ($app.friendLogInitStatus) { - this.getGroup({ groupId: json.ownerId }); + groupRequest.getGroup({ groupId: json.ownerId }); } return; } @@ -1245,41 +253,6 @@ export default class extends baseClass { } }); - /** - * @param {{ - query: string, - n: number, - offset: number, - order: string, - sortBy: string - }} params - * @return { Promise<{json: any, params}> } - */ - API.groupSearch = function (params) { - return this.call(`groups`, { - method: 'GET', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:SEARCH', args); - return args; - }); - }; - - API.$on('GROUP:SEARCH', function (args) { - for (var json of args.json) { - this.$emit('GROUP', { - json, - params: { - groupId: json.id - } - }); - } - }); - /** * @param {{ groupId: string }} params * @return { Promise<{json: any, params}> } @@ -1288,7 +261,7 @@ export default class extends baseClass { return new Promise((resolve, reject) => { var ref = this.cachedGroups.get(params.groupId); if (typeof ref === 'undefined') { - this.getGroup(params).catch(reject).then(resolve); + groupRequest.getGroup(params).catch(reject).then(resolve); } else { resolve({ cache: true, @@ -1451,7 +424,7 @@ export default class extends baseClass { } } // update myMember without fetching member - if (json.userId === this.currentUser.id) { + if (json?.userId === this.currentUser.id) { var ref = this.cachedGroups.get(json.groupId); if (typeof ref !== 'undefined') { this.$emit('GROUP', { @@ -1492,71 +465,21 @@ export default class extends baseClass { }); } }; - - API.$on('LOGOUT', function () { - $app.groupDialog.visible = false; - $app.inviteGroupDialog.visible = false; - $app.groupPostEditDialog.visible = false; - }); - - /** - * @param {{ - groupId: string, - galleryId: string, - n: number, - offset: number - }} params - * @return { Promise<{json: any, params}> } - */ - API.getGroupGallery = function (params) { - return this.call( - `groups/${params.groupId}/galleries/${params.galleryId}`, - { - method: 'GET', - params: { - n: params.n, - offset: params.offset - } - } - ).then((json) => { - var args = { - json, - params - }; - this.$emit('GROUP:GALLERY', args); - return args; - }); - }; - - API.$on('GROUP:GALLERY', function (args) { - for (var json of args.json) { - if ($app.groupDialog.id === json.groupId) { - if (!$app.groupDialog.galleries[json.galleryId]) { - $app.groupDialog.galleries[json.galleryId] = []; - } - $app.groupDialog.galleries[json.galleryId].push(json); - } - } - }); } _data = { currentUserGroupsInit: false, - groupDialogLastActiveTab: '', - groupDialogLastMembers: '', - groupDialogLastGallery: '', + // maybe unnecessary + // groupDialogLastMembers: '', + // groupDialogLastGallery: '', groupMembersSearchTimer: null, groupMembersSearchPending: false, - isGroupMembersLoading: false, - isGroupMembersDone: false, isGroupGalleryLoading: false, - loadMoreGroupMembersParams: {}, - groupMemberModerationTableForceUpdate: 0, - isGroupLogsExportDialogVisible: false, groupDialog: { visible: false, loading: false, + isGetGroupDialogGroupLoading: false, treeData: [], id: '', inGroup: false, @@ -1589,176 +512,10 @@ export default class extends baseClass { userId: '', userIds: [], userObject: {} - }, - groupPostEditDialog: { - visible: false, - groupRef: {}, - title: '', - text: '', - sendNotification: true, - visibility: 'group', - roleIds: [], - postId: '', - groupId: '' - }, - groupMemberModeration: { - visible: false, - loading: false, - id: '', - groupRef: {}, - auditLogTypes: [], - selectedAuditLogTypes: [], - note: '', - selectedUsers: new Map(), - selectedUsersArray: [], - selectedRoles: [], - progressCurrent: 0, - progressTotal: 0, - selectUserId: '' - }, - groupMemberModerationTable: { - data: [], - tableProps: { - stripe: true, - size: 'mini' - }, - pageSize: 15, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [10, 15, 25, 50, 100] - } - }, - groupBansModerationTable: { - data: [], - filters: [ - { - prop: ['$displayName'], - value: '' - } - ], - tableProps: { - stripe: true, - size: 'mini' - }, - pageSize: 15, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [10, 15, 25, 50, 100] - } - }, - groupLogsModerationTable: { - data: [], - filters: [ - { - prop: ['description'], - value: '' - } - ], - tableProps: { - stripe: true, - size: 'mini' - }, - pageSize: 15, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [10, 15, 25, 50, 100] - } - }, - groupInvitesModerationTable: { - data: [], - tableProps: { - stripe: true, - size: 'mini' - }, - pageSize: 15, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [10, 15, 25, 50, 100] - } - }, - groupJoinRequestsModerationTable: { - data: [], - tableProps: { - stripe: true, - size: 'mini' - }, - pageSize: 15, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [10, 15, 25, 50, 100] - } - }, - groupBlockedModerationTable: { - data: [], - tableProps: { - stripe: true, - size: 'mini' - }, - pageSize: 15, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [10, 15, 25, 50, 100] - } - }, - checkedGroupLogsExportLogsOptions: [ - 'created_at', - 'eventType', - 'actorDisplayName', - 'description', - 'data' - ], - checkGroupsLogsExportLogsOptions: [ - { - label: 'created_at', - text: 'dialog.group_member_moderation.created_at' - }, - { - label: 'eventType', - text: 'dialog.group_member_moderation.type' - }, - { - label: 'actorDisplayName', - text: 'dialog.group_member_moderation.display_name' - }, - { - label: 'description', - text: 'dialog.group_member_moderation.description' - }, - { - label: 'data', - text: 'dialog.group_member_moderation.data' - } - ], - groupLogsExportContent: '' + } }; _methods = { - confirmDeleteGroupPost(post) { - this.$confirm( - 'Are you sure you want to delete this post?', - 'Confirm', - { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: (action) => { - if (action === 'confirm') { - API.deleteGroupPost({ - groupId: post.groupId, - postId: post.id - }); - } - } - } - ); - }, - blockGroup(groupId) { this.$confirm( 'Are you sure you want to block this group?', @@ -1769,9 +526,23 @@ export default class extends baseClass { type: 'info', callback: (action) => { if (action === 'confirm') { - API.blockGroup({ - groupId - }); + groupRequest + .blockGroup({ + groupId + }) + .then((args) => { + // API.$on('GROUP:BLOCK', function (args) { + if ( + this.groupDialog.visible && + this.groupDialog.id === + args.params.groupId + ) { + this.showGroupDialog( + args.params.groupId + ); + } + // }); + }); } } } @@ -1788,187 +559,30 @@ export default class extends baseClass { type: 'info', callback: (action) => { if (action === 'confirm') { - API.unblockGroup({ - groupId, - userId: API.currentUser.id - }); + groupRequest + .unblockGroup({ + groupId, + userId: API.currentUser.id + }) + .then((args) => { + // API.$on('GROUP:UNBLOCK', function (args) { + if ( + this.groupDialog.visible && + this.groupDialog.id === + args.params.groupId + ) { + this.showGroupDialog( + args.params.groupId + ); + } + // }); + }); } } } ); }, - async getAllGroupBans(groupId) { - this.groupBansModerationTable.data = []; - var params = { - groupId, - n: 100, - offset: 0 - }; - var count = 50; // 5000 max - this.isGroupMembersLoading = true; - try { - for (var i = 0; i < count; i++) { - var args = await API.getGroupBans(params); - params.offset += params.n; - if (args.json.length < params.n) { - break; - } - if (!this.groupMemberModeration.visible) { - break; - } - } - } catch (err) { - this.$message({ - message: 'Failed to get group bans', - type: 'error' - }); - } finally { - this.isGroupMembersLoading = false; - } - }, - - async getAllGroupLogs(groupId) { - this.groupLogsModerationTable.data = []; - var params = { - groupId, - n: 100, - offset: 0 - }; - if (this.groupMemberModeration.selectedAuditLogTypes.length) { - params.eventTypes = - this.groupMemberModeration.selectedAuditLogTypes; - } - var count = 50; // 5000 max - this.isGroupMembersLoading = true; - try { - for (var i = 0; i < count; i++) { - var args = await API.getGroupLogs(params); - params.offset += params.n; - if (!args.json.hasNext) { - break; - } - if (!this.groupMemberModeration.visible) { - break; - } - } - } catch (err) { - this.$message({ - message: 'Failed to get group logs', - type: 'error' - }); - } finally { - this.isGroupMembersLoading = false; - } - }, - - getAuditLogTypeName(auditLogType) { - if (!auditLogType) { - return ''; - } - return auditLogType - .replace('group.', '') - .replace(/\./g, ' ') - .replace(/\b\w/g, (l) => l.toUpperCase()); - }, - - async getAllGroupInvitesAndJoinRequests(groupId) { - await this.getAllGroupInvites(groupId); - await this.getAllGroupJoinRequests(groupId); - await this.getAllGroupBlockedRequests(groupId); - }, - - async getAllGroupInvites(groupId) { - this.groupInvitesModerationTable.data = []; - var params = { - groupId, - n: 100, - offset: 0 - }; - var count = 50; // 5000 max - this.isGroupMembersLoading = true; - try { - for (var i = 0; i < count; i++) { - var args = await API.getGroupInvites(params); - params.offset += params.n; - if (args.json.length < params.n) { - break; - } - if (!this.groupMemberModeration.visible) { - break; - } - } - } catch (err) { - this.$message({ - message: 'Failed to get group invites', - type: 'error' - }); - } finally { - this.isGroupMembersLoading = false; - } - }, - - async getAllGroupJoinRequests(groupId) { - this.groupJoinRequestsModerationTable.data = []; - var params = { - groupId, - n: 100, - offset: 0 - }; - var count = 50; // 5000 max - this.isGroupMembersLoading = true; - try { - for (var i = 0; i < count; i++) { - var args = await API.getGroupJoinRequests(params); - params.offset += params.n; - if (args.json.length < params.n) { - break; - } - if (!this.groupMemberModeration.visible) { - break; - } - } - } catch (err) { - this.$message({ - message: 'Failed to get group join requests', - type: 'error' - }); - } finally { - this.isGroupMembersLoading = false; - } - }, - - async getAllGroupBlockedRequests(groupId) { - this.groupBlockedModerationTable.data = []; - var params = { - groupId, - n: 100, - offset: 0, - blocked: true - }; - var count = 50; // 5000 max - this.isGroupMembersLoading = true; - try { - for (var i = 0; i < count; i++) { - var args = await API.getGroupJoinRequests(params); - params.offset += params.n; - if (args.json.length < params.n) { - break; - } - if (!this.groupMemberModeration.visible) { - break; - } - } - } catch (err) { - this.$message({ - message: 'Failed to get group join requests', - type: 'error' - }); - } finally { - this.isGroupMembersLoading = false; - } - }, - async groupOwnerChange(ref, oldUserId, newUserId) { var oldUser = await userRequest.getCachedUser({ userId: oldUserId @@ -2101,7 +715,7 @@ export default class extends baseClass { console.log( `Fetching group with missing roles ${groupId}` ); - const args = await API.getGroup({ + const args = await groupRequest.getGroup({ groupId, includeRoles: true }); @@ -2120,7 +734,9 @@ export default class extends baseClass { }, async getCurrentUserGroups() { - var args = await API.getGroups({ userId: API.currentUser.id }); + var args = await groupRequest.getGroups({ + userId: API.currentUser.id + }); API.currentUserGroups.clear(); for (var group of args.json) { var ref = API.applyGroup(group); @@ -2128,7 +744,9 @@ export default class extends baseClass { API.currentUserGroups.set(group.id, ref); } } - await API.getGroupPermissions({ userId: API.currentUser.id }); + await groupRequest.getGroupPermissions({ + userId: API.currentUser.id + }); this.saveCurrentUserGroups(); }, @@ -2136,15 +754,6 @@ export default class extends baseClass { if (!groupId) { return; } - if ( - this.groupMemberModeration.visible && - this.groupMemberModeration.id !== groupId - ) { - this.groupMemberModeration.visible = false; - } - this.$nextTick(() => - $app.adjustDialogZ(this.$refs.groupDialog.$el) - ); var D = this.groupDialog; D.visible = true; D.loading = true; @@ -2159,13 +768,9 @@ export default class extends baseClass { D.memberRoles = []; D.memberSearch = ''; D.memberSearchResults = []; - if (this.groupDialogLastGallery !== groupId) { - D.galleries = {}; - } - if (this.groupDialogLastMembers !== groupId) { - D.members = []; - D.memberFilter = this.groupDialogFilterOptions.everyone; - } + D.galleries = {}; + D.members = []; + D.memberFilter = this.groupDialogFilterOptions.everyone; API.getCachedGroup({ groupId }) @@ -2200,7 +805,9 @@ export default class extends baseClass { getGroupDialogGroup(groupId) { var D = this.groupDialog; - return API.getGroup({ groupId, includeRoles: true }) + D.isGetGroupDialogGroupLoading = false; + return groupRequest + .getGroup({ groupId, includeRoles: true }) .catch((err) => { throw err; }) @@ -2221,50 +828,53 @@ export default class extends baseClass { API.getAllGroupPosts({ groupId }); + D.isGetGroupDialogGroupLoading = true; if (D.inGroup) { - API.getGroupInstances({ - groupId - }); - } - if (this.$refs.groupDialogTabs.currentName === '0') { - this.groupDialogLastActiveTab = $t( - 'dialog.group.info.header' - ); - } else if ( - this.$refs.groupDialogTabs.currentName === '1' - ) { - 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 === '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(); + groupRequest + .getGroupInstances({ + groupId + }) + .then((args) => { + // API.$on('GROUP:INSTANCES', function (args) { + if ( + this.groupDialog.id === + args.params.groupId + ) { + this.applyGroupDialogInstances( + args.json.instances + ); + } + // }); + + // API.$on('GROUP:INSTANCES', function (args) { + for (const json of args.json.instances) { + this.$emit('INSTANCE', { + json, + params: { + fetchedAt: args.json.fetchedAt + } + }); + worldRequest + .getCachedWorld({ + worldId: json.world.id + }) + .then((args1) => { + json.world = args1.ref; + return args1; + }); + // get queue size etc + instanceRequest.getInstance({ + worldId: json.worldId, + instanceId: json.instanceId + }); + } + // }); + }); } } + this.$nextTick( + () => (D.isGetGroupDialogGroupLoading = false) + ); return args1; }); }, @@ -2278,17 +888,8 @@ export default class extends baseClass { case 'Refresh': this.showGroupDialog(D.id); break; - case 'Share': - this.copyGroupUrl(D.ref.$url); - break; - case 'Moderation Tools': - this.showGroupMemberModerationDialog(D.id); - break; - case 'Create Post': - this.showGroupPostEditDialog(D.id, null); - break; case 'Leave Group': - this.leaveGroup(D.id); + this.leaveGroupPrompt(D.id); break; case 'Block Group': this.blockGroup(D.id); @@ -2317,70 +918,6 @@ export default class extends baseClass { } }, - groupDialogTabClick(obj) { - var groupId = this.groupDialog.id; - if (this.groupDialogLastActiveTab === obj.label) { - return; - } - 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(); - } - } else if (obj.label === $t('dialog.group.gallery.header')) { - if (this.groupDialogLastGallery !== groupId) { - this.groupDialogLastGallery = groupId; - this.getGroupGalleries(); - } - } else if (obj.label === $t('dialog.group.json.header')) { - this.refreshGroupDialogTreeData(); - } - this.groupDialogLastActiveTab = obj.label; - }, - - refreshGroupDialogTreeData() { - var D = this.groupDialog; - D.treeData = $utils.buildTreeData({ - group: D.ref, - posts: D.posts, - instances: D.instances, - members: D.members, - galleries: D.galleries - }); - }, - - joinGroup(groupId) { - if (!groupId) { - return null; - } - return API.joinGroup({ - groupId - }).then((args) => { - if (args.json.membershipStatus === 'member') { - this.$message({ - message: 'Group joined', - type: 'success' - }); - } else if (args.json.membershipStatus === 'requested') { - this.$message({ - message: 'Group join request sent', - type: 'success' - }); - } - return args; - }); - }, - - leaveGroup(groupId) { - return API.leaveGroup({ - groupId - }); - }, - leaveGroupPrompt(groupId) { this.$confirm( 'Are you sure you want to leave this group?', @@ -2391,74 +928,87 @@ export default class extends baseClass { type: 'info', callback: (action) => { if (action === 'confirm') { - this.leaveGroup(groupId); + groupRequest + .leaveGroup({ + groupId + }) + .then((args) => { + // API.$on('GROUP:LEAVE', function (args) { + const groupId = args.params.groupId; + if ( + this.groupDialog.visible && + this.groupDialog.id === groupId + ) { + this.groupDialog.inGroup = false; + this.getGroupDialogGroup(groupId); + } + if ( + this.userDialog.visible && + this.userDialog.id === + this.currentUser.id && + this.userDialog.representedGroup.id === + groupId + ) { + this.getCurrentUserRepresentedGroup(); + } + // }); + }); } } } ); }, - cancelGroupRequest(groupId) { - return API.cancelGroupRequest({ - groupId - }); - }, - - setGroupRepresentation(groupId) { - return API.setGroupRepresentation(groupId, { - isRepresenting: true - }); - }, - - clearGroupRepresentation(groupId) { - return API.setGroupRepresentation(groupId, { - isRepresenting: false - }); - }, - setGroupVisibility(groupId, visibility) { - return API.setGroupMemberProps(API.currentUser.id, groupId, { - visibility - }).then((args) => { - this.$message({ - message: 'Group visibility updated', - type: 'success' + return groupRequest + .setGroupMemberProps(API.currentUser.id, groupId, { + visibility + }) + .then((args) => { + this.$message({ + message: 'Group visibility updated', + type: 'success' + }); + return args; }); - return args; - }); }, setGroupSubscription(groupId, subscribe) { - return API.setGroupMemberProps(API.currentUser.id, groupId, { - isSubscribedToAnnouncements: subscribe - }).then((args) => { - this.$message({ - message: 'Group subscription updated', - type: 'success' + return groupRequest + .setGroupMemberProps(API.currentUser.id, groupId, { + isSubscribedToAnnouncements: subscribe + }) + .then((args) => { + this.$message({ + message: 'Group subscription updated', + type: 'success' + }); + return args; }); - return args; - }); }, onGroupJoined(groupId) { - if ( - this.groupMemberModeration.visible && - this.groupMemberModeration.id === groupId - ) { - // ignore this event if we were the one to trigger it - return; - } + // NOTE: don't know why need this + // if ( + // this.groupMemberModeration.visible && + // this.groupMemberModeration.id === groupId + // ) { + // // ignore this event if we were the one to trigger it + // return; + // } if (!API.currentUserGroups.has(groupId)) { API.currentUserGroups.set(groupId, { id: groupId, name: '', iconUrl: '' }); - API.getGroup({ groupId, includeRoles: true }).then((args) => { - API.applyGroup(args.json); // make sure this runs before saveCurrentUserGroups - this.saveCurrentUserGroups(); - return args; - }); + groupRequest + .getGroup({ groupId, includeRoles: true }) + .then((args) => { + API.applyGroup(args.json); // make sure this runs before saveCurrentUserGroups + this.saveCurrentUserGroups(); + return args; + }); } }, @@ -2474,56 +1024,6 @@ export default class extends baseClass { } }, - groupMembersSearchDebounce() { - var D = this.groupDialog; - var search = D.memberSearch; - D.memberSearchResults = []; - if (!search || search.length < 3) { - this.setGroupMemberModerationTable(D.members); - return; - } - this.isGroupMembersLoading = true; - API.getGroupMembersSearch({ - groupId: D.id, - query: search, - n: 100, - offset: 0 - }) - .then((args) => { - if (D.id === args.params.groupId) { - D.memberSearchResults = args.json.results; - this.setGroupMemberModerationTable(args.json.results); - } - }) - .finally(() => { - this.isGroupMembersLoading = false; - }); - }, - - groupMembersSearch() { - if (this.groupMembersSearchTimer) { - this.groupMembersSearchPending = true; - } else { - this.groupMembersSearchExecute(); - this.groupMembersSearchTimer = setTimeout(() => { - if (this.groupMembersSearchPending) { - this.groupMembersSearchExecute(); - } - this.groupMembersSearchTimer = null; - }, 500); - } - }, - - groupMembersSearchExecute() { - try { - this.groupMembersSearchDebounce(); - } catch (err) { - console.error(err); - } - this.groupMembersSearchTimer = null; - this.groupMembersSearchPending = false; - }, - updateGroupPostSearch() { var D = this.groupDialog; var search = D.postsSearch.toLowerCase(); @@ -2541,183 +1041,19 @@ export default class extends baseClass { }); }, - async getGroupDialogGroupMembers() { - var D = this.groupDialog; - D.members = []; - this.isGroupMembersDone = false; - this.loadMoreGroupMembersParams = { - n: 100, - offset: 0, - groupId: D.id - }; - if (D.memberSortOrder.value) { - this.loadMoreGroupMembersParams.sort = D.memberSortOrder.value; - } - if (D.memberFilter.id !== null) { - this.loadMoreGroupMembersParams.roleId = D.memberFilter.id; - } - if (D.inGroup) { - await API.getGroupMember({ - groupId: D.id, + getCurrentUserRepresentedGroup() { + return groupRequest + .getRepresentedGroup({ userId: API.currentUser.id - }).then((args) => { - if (args.json) { - args.json.user = API.currentUser; - if (D.memberFilter.id === null) { - // when flitered by role don't include self - D.members.push(args.json); - } - } - return args; - }); - } - await this.loadMoreGroupMembers(); - }, - - async loadMoreGroupMembers() { - if (this.isGroupMembersDone || this.isGroupMembersLoading) { - return; - } - var D = this.groupDialog; - var params = this.loadMoreGroupMembersParams; - D.memberSearch = ''; - this.isGroupMembersLoading = true; - await API.getGroupMembers(params) - .finally(() => { - this.isGroupMembersLoading = false; }) .then((args) => { - for (var i = 0; i < args.json.length; i++) { - var member = args.json[i]; - if (member.userId === API.currentUser.id) { - if ( - D.members.length > 0 && - D.members[0].userId === API.currentUser.id - ) { - // remove duplicate and keep sort order - D.members.splice(0, 1); - } - break; - } - } - if (args.json.length < params.n) { - this.isGroupMembersDone = true; - } - D.members = [...D.members, ...args.json]; - this.setGroupMemberModerationTable(D.members); - params.offset += params.n; + this.userDialog.representedGroup = args.json; return args; - }) - .catch((err) => { - this.isGroupMembersDone = true; - throw err; }); }, - async loadAllGroupMembers() { - if (this.isGroupMembersLoading) { - return; - } - await this.getGroupDialogGroupMembers(); - while (this.groupDialog.visible && !this.isGroupMembersDone) { - this.isGroupMembersLoading = true; - await new Promise((resolve) => { - workerTimers.setTimeout(resolve, 1000); - }); - this.isGroupMembersLoading = false; - await this.loadMoreGroupMembers(); - } - }, - - async setGroupMemberSortOrder(sortOrder) { - var D = this.groupDialog; - if (D.memberSortOrder === sortOrder) { - return; - } - D.memberSortOrder = sortOrder; - await this.getGroupDialogGroupMembers(); - }, - - async setGroupMemberFilter(filter) { - var D = this.groupDialog; - if (D.memberFilter === filter) { - return; - } - D.memberFilter = filter; - await this.getGroupDialogGroupMembers(); - }, - - getCurrentUserRepresentedGroup() { - return API.getRepresentedGroup({ - userId: API.currentUser.id - }).then((args) => { - this.userDialog.representedGroup = args.json; - return args; - }); - }, - - hasGroupPermission(ref, permission) { - if ( - ref && - ref.myMember && - ref.myMember.permissions && - (ref.myMember.permissions.includes('*') || - ref.myMember.permissions.includes(permission)) - ) { - return true; - } - return false; - }, - - async getGroupGalleries() { - this.groupDialog.galleries = {}; - this.$refs.groupDialogGallery.currentName = '0'; // select first tab - this.isGroupGalleryLoading = true; - for (var i = 0; i < this.groupDialog.ref.galleries.length; i++) { - var gallery = this.groupDialog.ref.galleries[i]; - await this.getGroupGallery(this.groupDialog.id, gallery.id); - } - this.isGroupGalleryLoading = false; - }, - - async getGroupGallery(groupId, galleryId) { - try { - var params = { - groupId, - galleryId, - n: 100, - offset: 0 - }; - var count = 50; // 5000 max - for (var i = 0; i < count; i++) { - var args = await API.getGroupGallery(params); - params.offset += 100; - if (args.json.length < 100) { - break; - } - } - } catch (err) { - console.error(err); - } - }, - - groupGalleryStatus(gallery) { - var style = {}; - if (!gallery.membersOnly) { - style.blue = true; - } else if (!gallery.roleIdsToView) { - style.green = true; - } else { - style.red = true; - } - return style; - }, - showInviteGroupDialog(groupId, userId) { - this.$nextTick(() => - $app.adjustDialogZ(this.$refs.inviteGroupDialog.$el) - ); - var D = this.inviteGroupDialog; + const D = this.inviteGroupDialog; D.userIds = ''; D.groups = []; D.groupId = groupId; @@ -2725,957 +1061,6 @@ export default class extends baseClass { D.userId = userId; D.userObject = {}; D.visible = true; - if (groupId) { - API.getCachedGroup({ - groupId - }) - .then((args) => { - D.groupName = args.ref.name; - }) - .catch(() => { - D.groupId = ''; - }); - this.isAllowedToInviteToGroup(); - } - - if (userId) { - userRequest.getCachedUser({ userId }).then((args) => { - D.userObject = args.ref; - }); - D.userIds = [userId]; - } - }, - - sendGroupInvite() { - this.$confirm('Continue? Invite User(s) To Group', 'Confirm', { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: (action) => { - var D = this.inviteGroupDialog; - if (action !== 'confirm' || D.loading === true) { - return; - } - D.loading = true; - var inviteLoop = () => { - if (D.userIds.length === 0) { - D.loading = false; - return; - } - var receiverUserId = D.userIds.shift(); - API.sendGroupInvite({ - groupId: D.groupId, - userId: receiverUserId - }) - .then(inviteLoop) - .catch(() => { - D.loading = false; - }); - }; - inviteLoop(); - } - }); - }, - - isAllowedToInviteToGroup() { - var D = this.inviteGroupDialog; - var groupId = D.groupId; - if (!groupId) { - return; - } - D.loading = true; - API.getGroup({ groupId }) - .then((args) => { - if ( - this.hasGroupPermission( - args.ref, - 'group-invites-manage' - ) - ) { - return args; - } - // not allowed to invite - D.groupId = ''; - this.$message({ - type: 'error', - message: 'You are not allowed to invite to this group' - }); - return args; - }) - .finally(() => { - D.loading = false; - }); - }, - - showGroupPostEditDialog(groupId, post) { - this.$nextTick(() => - $app.adjustDialogZ(this.$refs.groupPostEditDialog.$el) - ); - var D = this.groupPostEditDialog; - D.sendNotification = true; - D.groupRef = {}; - D.title = ''; - D.text = ''; - D.visibility = 'group'; - D.roleIds = []; - D.postId = ''; - D.groupId = groupId; - $app.gallerySelectDialog.selectedFileId = ''; - $app.gallerySelectDialog.selectedImageUrl = ''; - if (post) { - D.title = post.title; - D.text = post.text; - D.visibility = post.visibility; - D.roleIds = post.roleIds; - D.postId = post.id; - $app.gallerySelectDialog.selectedFileId = post.imageId; - $app.gallerySelectDialog.selectedImageUrl = post.imageUrl; - } - API.getCachedGroup({ groupId }).then((args) => { - D.groupRef = args.ref; - }); - D.visible = true; - }, - - editGroupPost() { - var D = this.groupPostEditDialog; - if (!D.groupId || !D.postId) { - return; - } - var params = { - groupId: D.groupId, - postId: D.postId, - title: D.title, - text: D.text, - roleIds: D.roleIds, - visibility: D.visibility, - imageId: null - }; - if (this.gallerySelectDialog.selectedFileId) { - params.imageId = this.gallerySelectDialog.selectedFileId; - } - API.editGroupPost(params).then((args) => { - this.$message({ - message: 'Group post edited', - type: 'success' - }); - return args; - }); - D.visible = false; - }, - - createGroupPost() { - var D = this.groupPostEditDialog; - var params = { - groupId: D.groupId, - title: D.title, - text: D.text, - roleIds: D.roleIds, - visibility: D.visibility, - sendNotification: D.sendNotification, - imageId: null - }; - if (this.gallerySelectDialog.selectedFileId) { - params.imageId = this.gallerySelectDialog.selectedFileId; - } - API.createGroupPost(params).then((args) => { - this.$message({ - message: 'Group post created', - type: 'success' - }); - return args; - }); - D.visible = false; - }, - - setGroupMemberModerationTable(data) { - if (!this.groupMemberModeration.visible) { - return; - } - for (var i = 0; i < data.length; i++) { - var member = data[i]; - member.$selected = this.groupMemberModeration.selectedUsers.has( - member.userId - ); - } - this.groupMemberModerationTable.data = data; - // force redraw - this.groupMemberModerationTableForceUpdate++; - }, - - showGroupMemberModerationDialog(groupId) { - this.$nextTick(() => - $app.adjustDialogZ(this.$refs.groupMemberModeration.$el) - ); - if (groupId !== this.groupDialog.id) { - return; - } - var D = this.groupMemberModeration; - D.id = groupId; - D.selectedUsers.clear(); - D.selectedUsersArray = []; - D.selectedRoles = []; - D.groupRef = {}; - D.auditLogTypes = []; - D.selectedAuditLogTypes = []; - API.getCachedGroup({ groupId }).then((args) => { - D.groupRef = args.ref; - if (this.hasGroupPermission(D.groupRef, 'group-audit-view')) { - API.getGroupAuditLogTypes({ groupId }); - } - }); - this.groupMemberModerationTableForceUpdate = 0; - D.visible = true; - this.setGroupMemberModerationTable(this.groupDialog.members); - }, - - groupMemberModerationTableSelectionChange(row) { - var D = this.groupMemberModeration; - if (row.$selected && !D.selectedUsers.has(row.userId)) { - D.selectedUsers.set(row.userId, row); - } else if (!row.$selected && D.selectedUsers.has(row.userId)) { - D.selectedUsers.delete(row.userId); - } - D.selectedUsersArray = Array.from(D.selectedUsers.values()); - // force redraw - this.groupMemberModerationTableForceUpdate++; - }, - - deleteSelectedGroupMember(user) { - var D = this.groupMemberModeration; - D.selectedUsers.delete(user.userId); - D.selectedUsersArray = Array.from(D.selectedUsers.values()); - for ( - var i = 0; - i < this.groupMemberModerationTable.data.length; - i++ - ) { - var row = this.groupMemberModerationTable.data[i]; - if (row.userId === user.userId) { - row.$selected = false; - break; - } - } - for ( - var i = 0; - i < this.groupBansModerationTable.data.length; - i++ - ) { - var row = this.groupBansModerationTable.data[i]; - if (row.userId === user.userId) { - row.$selected = false; - break; - } - } - for ( - var i = 0; - i < this.groupInvitesModerationTable.data.length; - i++ - ) { - var row = this.groupInvitesModerationTable.data[i]; - if (row.userId === user.userId) { - row.$selected = false; - break; - } - } - for ( - var i = 0; - i < this.groupJoinRequestsModerationTable.data.length; - i++ - ) { - var row = this.groupJoinRequestsModerationTable.data[i]; - if (row.userId === user.userId) { - row.$selected = false; - break; - } - } - for ( - var i = 0; - i < this.groupBlockedModerationTable.data.length; - i++ - ) { - var row = this.groupBlockedModerationTable.data[i]; - if (row.userId === user.userId) { - row.$selected = false; - break; - } - } - - // force redraw - this.groupMemberModerationTableForceUpdate++; - }, - - clearSelectedGroupMembers() { - var D = this.groupMemberModeration; - D.selectedUsers.clear(); - D.selectedUsersArray = []; - for ( - var i = 0; - i < this.groupMemberModerationTable.data.length; - i++ - ) { - var row = this.groupMemberModerationTable.data[i]; - row.$selected = false; - } - for ( - var i = 0; - i < this.groupBansModerationTable.data.length; - i++ - ) { - var row = this.groupBansModerationTable.data[i]; - row.$selected = false; - } - for ( - var i = 0; - i < this.groupInvitesModerationTable.data.length; - i++ - ) { - var row = this.groupInvitesModerationTable.data[i]; - row.$selected = false; - } - for ( - var i = 0; - i < this.groupJoinRequestsModerationTable.data.length; - i++ - ) { - var row = this.groupJoinRequestsModerationTable.data[i]; - row.$selected = false; - } - for ( - var i = 0; - i < this.groupBlockedModerationTable.data.length; - i++ - ) { - var row = this.groupBlockedModerationTable.data[i]; - row.$selected = false; - } - // force redraw - this.groupMemberModerationTableForceUpdate++; - }, - - selectAllGroupMembers() { - var D = this.groupMemberModeration; - for ( - var i = 0; - i < this.groupMemberModerationTable.data.length; - i++ - ) { - var row = this.groupMemberModerationTable.data[i]; - row.$selected = true; - D.selectedUsers.set(row.userId, row); - } - D.selectedUsersArray = Array.from(D.selectedUsers.values()); - // force redraw - this.groupMemberModerationTableForceUpdate++; - }, - - selectAllGroupBans() { - var D = this.groupMemberModeration; - for ( - var i = 0; - i < this.groupBansModerationTable.data.length; - i++ - ) { - var row = this.groupBansModerationTable.data[i]; - row.$selected = true; - D.selectedUsers.set(row.userId, row); - } - D.selectedUsersArray = Array.from(D.selectedUsers.values()); - // force redraw - this.groupMemberModerationTableForceUpdate++; - }, - - selectAllGroupInvites() { - var D = this.groupMemberModeration; - for ( - var i = 0; - i < this.groupInvitesModerationTable.data.length; - i++ - ) { - var row = this.groupInvitesModerationTable.data[i]; - row.$selected = true; - D.selectedUsers.set(row.userId, row); - } - D.selectedUsersArray = Array.from(D.selectedUsers.values()); - // force redraw - this.groupMemberModerationTableForceUpdate++; - }, - - selectAllGroupJoinRequests() { - var D = this.groupMemberModeration; - for ( - var i = 0; - i < this.groupJoinRequestsModerationTable.data.length; - i++ - ) { - var row = this.groupJoinRequestsModerationTable.data[i]; - row.$selected = true; - D.selectedUsers.set(row.userId, row); - } - D.selectedUsersArray = Array.from(D.selectedUsers.values()); - // force redraw - this.groupMemberModerationTableForceUpdate++; - }, - - selectAllGroupBlocked() { - var D = this.groupMemberModeration; - for ( - var i = 0; - i < this.groupBlockedModerationTable.data.length; - i++ - ) { - var row = this.groupBlockedModerationTable.data[i]; - row.$selected = true; - D.selectedUsers.set(row.userId, row); - } - D.selectedUsersArray = Array.from(D.selectedUsers.values()); - // force redraw - this.groupMemberModerationTableForceUpdate++; - }, - - async groupMembersKick() { - var D = this.groupMemberModeration; - var memberCount = D.selectedUsersArray.length; - D.progressTotal = memberCount; - for (var i = 0; i < memberCount; i++) { - if (!D.visible || !D.progressTotal) { - break; - } - var user = D.selectedUsersArray[i]; - D.progressCurrent = i + 1; - if (user.userId === API.currentUser.id) { - continue; - } - console.log(`Kicking ${user.userId} ${i + 1}/${memberCount}`); - try { - await API.kickGroupMember({ - groupId: D.id, - userId: user.userId - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Failed to kick group member: ${err}`, - type: 'error' - }); - } - } - this.$message({ - message: `Kicked ${memberCount} group members`, - type: 'success' - }); - D.progressCurrent = 0; - D.progressTotal = 0; - }, - - async groupMembersBan() { - var D = this.groupMemberModeration; - var memberCount = D.selectedUsersArray.length; - D.progressTotal = memberCount; - for (var i = 0; i < memberCount; i++) { - if (!D.visible || !D.progressTotal) { - break; - } - var user = D.selectedUsersArray[i]; - D.progressCurrent = i + 1; - if (user.userId === API.currentUser.id) { - continue; - } - console.log(`Banning ${user.userId} ${i + 1}/${memberCount}`); - try { - await API.banGroupMember({ - groupId: D.id, - userId: user.userId - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Failed to ban group member: ${err}`, - type: 'error' - }); - } - } - this.$message({ - message: `Banned ${memberCount} group members`, - type: 'success' - }); - D.progressCurrent = 0; - D.progressTotal = 0; - }, - - async groupMembersUnban() { - var D = this.groupMemberModeration; - var memberCount = D.selectedUsersArray.length; - D.progressTotal = memberCount; - - for (var i = 0; i < memberCount; i++) { - if (!D.visible || !D.progressTotal) { - break; - } - var user = D.selectedUsersArray[i]; - D.progressCurrent = i + 1; - if (user.userId === API.currentUser.id) { - continue; - } - console.log(`Unbanning ${user.userId} ${i + 1}/${memberCount}`); - try { - await API.unbanGroupMember({ - groupId: D.id, - userId: user.userId - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Failed to unban group member: ${err}`, - type: 'error' - }); - } - } - this.$message({ - message: `Unbanned ${memberCount} group members`, - type: 'success' - }); - D.progressCurrent = 0; - D.progressTotal = 0; - }, - - async groupMembersDeleteSentInvite() { - var D = this.groupMemberModeration; - var memberCount = D.selectedUsersArray.length; - D.progressTotal = memberCount; - for (var i = 0; i < memberCount; i++) { - if (!D.visible || !D.progressTotal) { - break; - } - var user = D.selectedUsersArray[i]; - D.progressCurrent = i + 1; - if (user.userId === API.currentUser.id) { - continue; - } - console.log( - `Deleting group invite ${user.userId} ${i + 1}/${memberCount}` - ); - try { - await API.deleteSentGroupInvite({ - groupId: D.id, - userId: user.userId - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Failed to delete group invites: ${err}`, - type: 'error' - }); - } - } - this.$message({ - message: `Deleted ${memberCount} group invites`, - type: 'success' - }); - D.progressCurrent = 0; - D.progressTotal = 0; - }, - - async groupMembersDeleteBlockedRequest() { - var D = this.groupMemberModeration; - var memberCount = D.selectedUsersArray.length; - D.progressTotal = memberCount; - for (var i = 0; i < memberCount; i++) { - if (!D.visible || !D.progressTotal) { - break; - } - var user = D.selectedUsersArray[i]; - D.progressCurrent = i + 1; - if (user.userId === API.currentUser.id) { - continue; - } - console.log( - `Deleting blocked group request ${user.userId} ${i + 1}/${memberCount}` - ); - try { - await API.deleteBlockedGroupRequest({ - groupId: D.id, - userId: user.userId - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Failed to delete blocked group requests: ${err}`, - type: 'error' - }); - } - } - this.$message({ - message: `Deleted ${memberCount} blocked group requests`, - type: 'success' - }); - D.progressCurrent = 0; - D.progressTotal = 0; - }, - - async groupMembersAcceptInviteRequest() { - var D = this.groupMemberModeration; - var memberCount = D.selectedUsersArray.length; - D.progressTotal = memberCount; - for (var i = 0; i < memberCount; i++) { - if (!D.visible || !D.progressTotal) { - break; - } - var user = D.selectedUsersArray[i]; - D.progressCurrent = i + 1; - if (user.userId === API.currentUser.id) { - continue; - } - console.log( - `Accepting group join request ${user.userId} ${i + 1}/${memberCount}` - ); - try { - await API.acceptGroupInviteRequest({ - groupId: D.id, - userId: user.userId - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Failed to accept group join requests: ${err}`, - type: 'error' - }); - } - } - this.$message({ - message: `Accepted ${memberCount} group join requests`, - type: 'success' - }); - D.progressCurrent = 0; - D.progressTotal = 0; - }, - - async groupMembersRejectInviteRequest() { - var D = this.groupMemberModeration; - var memberCount = D.selectedUsersArray.length; - D.progressTotal = memberCount; - for (var i = 0; i < memberCount; i++) { - if (!D.visible || !D.progressTotal) { - break; - } - var user = D.selectedUsersArray[i]; - D.progressCurrent = i + 1; - if (user.userId === API.currentUser.id) { - continue; - } - console.log( - `Rejecting group join request ${user.userId} ${i + 1}/${memberCount}` - ); - try { - await API.rejectGroupInviteRequest({ - groupId: D.id, - userId: user.userId - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Failed to reject group join requests: ${err}`, - type: 'error' - }); - } - this.$message({ - message: `Rejected ${memberCount} group join requests`, - type: 'success' - }); - D.progressCurrent = 0; - D.progressTotal = 0; - } - }, - - async groupMembersBlockJoinRequest() { - var D = this.groupMemberModeration; - var memberCount = D.selectedUsersArray.length; - D.progressTotal = memberCount; - for (var i = 0; i < memberCount; i++) { - if (!D.visible || !D.progressTotal) { - break; - } - var user = D.selectedUsersArray[i]; - D.progressCurrent = i + 1; - if (user.userId === API.currentUser.id) { - continue; - } - console.log( - `Blocking group join request ${user.userId} ${i + 1}/${memberCount}` - ); - try { - await API.blockGroupInviteRequest({ - groupId: D.id, - userId: user.userId - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Failed to block group join requests: ${err}`, - type: 'error' - }); - } - } - this.$message({ - message: `Blocked ${memberCount} group join requests`, - type: 'success' - }); - D.progressCurrent = 0; - D.progressTotal = 0; - }, - - async groupMembersSaveNote() { - var D = this.groupMemberModeration; - var memberCount = D.selectedUsersArray.length; - D.progressTotal = memberCount; - for (var i = 0; i < memberCount; i++) { - if (!D.visible || !D.progressTotal) { - break; - } - var user = D.selectedUsersArray[i]; - D.progressCurrent = i + 1; - if (user.managerNotes === D.note) { - continue; - } - console.log( - `Setting note ${D.note} ${user.userId} ${ - i + 1 - }/${memberCount}` - ); - try { - await API.setGroupMemberProps(user.userId, D.id, { - managerNotes: D.note - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Failed to set group member note: ${err}`, - type: 'error' - }); - } - } - this.$message({ - message: `Saved notes for ${memberCount} group members`, - type: 'success' - }); - D.progressCurrent = 0; - D.progressTotal = 0; - }, - - async groupMembersAddRoles() { - var D = this.groupMemberModeration; - var memberCount = D.selectedUsersArray.length; - D.progressTotal = memberCount; - for (var i = 0; i < memberCount; i++) { - if (!D.visible || !D.progressTotal) { - break; - } - var user = D.selectedUsersArray[i]; - D.progressCurrent = i + 1; - var rolesToAdd = []; - D.selectedRoles.forEach((roleId) => { - if (!user.roleIds.includes(roleId)) { - rolesToAdd.push(roleId); - } - }); - - if (!rolesToAdd.length) { - continue; - } - for (var j = 0; j < rolesToAdd.length; j++) { - var roleId = rolesToAdd[j]; - console.log( - `Adding role: ${roleId} ${user.userId} ${ - i + 1 - }/${memberCount}` - ); - try { - await API.addGroupMemberRole({ - groupId: D.id, - userId: user.userId, - roleId - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Failed to add group member roles: ${err}`, - type: 'error' - }); - } - } - } - this.$message({ - message: 'Added group member roles', - type: 'success' - }); - D.progressCurrent = 0; - D.progressTotal = 0; - }, - - async groupMembersRemoveRoles() { - var D = this.groupMemberModeration; - var memberCount = D.selectedUsersArray.length; - D.progressTotal = memberCount; - for (var i = 0; i < memberCount; i++) { - if (!D.visible || !D.progressTotal) { - break; - } - var user = D.selectedUsersArray[i]; - D.progressCurrent = i + 1; - var rolesToRemove = []; - D.selectedRoles.forEach((roleId) => { - if (user.roleIds.includes(roleId)) { - rolesToRemove.push(roleId); - } - }); - if (!rolesToRemove.length) { - continue; - } - for (var j = 0; j < rolesToRemove.length; j++) { - var roleId = rolesToRemove[j]; - console.log( - `Removing role ${roleId} ${user.userId} ${ - i + 1 - }/${memberCount}` - ); - try { - await API.removeGroupMemberRole({ - groupId: D.id, - userId: user.userId, - roleId - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Failed to remove group member roles: ${err}`, - type: 'error' - }); - } - } - } - this.$message({ - message: 'Roles removed', - type: 'success' - }); - D.progressCurrent = 0; - D.progressTotal = 0; - }, - - async selectGroupMemberUserId() { - var D = this.groupMemberModeration; - if (!D.selectUserId) { - return; - } - - var regexUserId = - /usr_[0-9A-Fa-f]{8}-([0-9A-Fa-f]{4}-){3}[0-9A-Fa-f]{12}/g; - var match = []; - var userIdList = new Set(); - while ((match = regexUserId.exec(D.selectUserId)) !== null) { - userIdList.add(match[0]); - } - if (userIdList.size === 0) { - // for those users missing the usr_ prefix - userIdList.add(D.selectUserId); - } - for (var userId of userIdList) { - try { - await this.addGroupMemberToSelection(userId); - } catch { - console.error(`Failed to add user ${userId}`); - } - } - - D.selectUserId = ''; - }, - - async addGroupMemberToSelection(userId) { - var D = this.groupMemberModeration; - - // fetch member if there is one - // banned members don't have a user object - - var member = {}; - var memberArgs = await API.getGroupMember({ - groupId: D.id, - userId - }); - if (memberArgs.json) { - member = API.applyGroupMember(memberArgs.json); - } - if (member.user) { - D.selectedUsers.set(member.userId, member); - D.selectedUsersArray = Array.from(D.selectedUsers.values()); - this.groupMemberModerationTableForceUpdate++; - return; - } - - var userArgs = await userRequest.getCachedUser({ - userId - }); - member.userId = userArgs.json.id; - member.user = userArgs.json; - member.displayName = userArgs.json.displayName; - - D.selectedUsers.set(member.userId, member); - D.selectedUsersArray = Array.from(D.selectedUsers.values()); - this.groupMemberModerationTableForceUpdate++; - }, - showGroupLogsExportDialog() { - this.$nextTick(() => - $app.adjustDialogZ(this.$refs.groupLogsExportDialogRef.$el) - ); - this.groupLogsExportContent = ''; - this.updateGrouptLogsExporContent(); - this.isGroupLogsExportDialogVisible = true; - }, - handleCopyGroupLogsExportContent(event) { - event.target.tagName === 'TEXTAREA' && event.target.select(); - navigator.clipboard - .writeText(this.groupLogsExportContent) - .then(() => { - this.$message({ - message: 'Copied successfully!', - type: 'success', - duration: 2000 - }); - }) - .catch((err) => { - console.error('Copy failed:', err); - this.$message.error('Copy failed!'); - }); - }, - updateGrouptLogsExporContent() { - const formatter = (str) => - /[\x00-\x1f,"]/.test(str) - ? `"${str.replace(/"/g, '""')}"` - : str; - - const sortedCheckedOptions = this.checkGroupsLogsExportLogsOptions - .filter((option) => - this.checkedGroupLogsExportLogsOptions.includes( - option.label - ) - ) - .map((option) => option.label); - - const header = sortedCheckedOptions.join(',') + '\n'; - - const content = this.groupLogsModerationTable.data - .map((item) => - sortedCheckedOptions - .map((key) => - formatter( - key === 'data' - ? JSON.stringify(item[key]) - : item[key] - ) - ) - .join(',') - ) - .join('\n'); - - this.groupLogsExportContent = header + content; } }; } diff --git a/src/classes/request/group.js b/src/classes/request/group.js new file mode 100644 index 00000000..b26397ad --- /dev/null +++ b/src/classes/request/group.js @@ -0,0 +1,773 @@ +const groupReq = { + /** + * @param {string} groupId + * @param {{isRepresenting: bool}} params + * @returns + */ + setGroupRepresentation(groupId, params) { + return window.API.call(`groups/${groupId}/representation`, { + method: 'PUT', + params + }).then((json) => { + const args = { + json, + groupId, + params + }; + return args; + }); + }, + + /** + * @param {{ groupId: string }} params + * @return { Promise<{json: any, params}> } + */ + cancelGroupRequest(params) { + return window.API.call(`groups/${params.groupId}/requests`, { + method: 'DELETE' + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + + /** + * @param {{ groupId: string, postId: string }} params + * @return { Promise<{json: any, params}> } + */ + deleteGroupPost(params) { + return window.API.call( + `groups/${params.groupId}/posts/${params.postId}`, + { + method: 'DELETE' + } + ).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + /** + * @param {{ groupId: string }} params + */ + getGroup(params) { + return window.API.call(`groups/${params.groupId}`, { + method: 'GET', + params: { + includeRoles: params.includeRoles || false + } + }).then((json) => { + const args = { + json, + params + }; + window.API.$emit('GROUP', args); + return args; + }); + }, + /** + * @param {{ userId: string }} params + * @return { Promise<{json: any, params}> } + */ + getRepresentedGroup(params) { + return window.API.call(`users/${params.userId}/groups/represented`, { + method: 'GET' + }).then((json) => { + const args = { + json, + params + }; + window.API.$emit('GROUP:REPRESENTED', args); + return args; + }); + }, + /** + * @param {{ userId: string }} params + * @return { Promise<{json: any, params}> } + */ + getGroups(params) { + return window.API.call(`users/${params.userId}/groups`, { + method: 'GET' + }).then((json) => { + const args = { + json, + params + }; + window.API.$emit('GROUP:LIST', args); + return args; + }); + }, + /** + * @param {{ groupId: string }} params + * @return { Promise<{json: any, params}> } + */ + joinGroup(params) { + return window.API.call(`groups/${params.groupId}/join`, { + method: 'POST' + }).then((json) => { + const args = { + json, + params + }; + window.API.$emit('GROUP:JOIN', args); + return args; + }); + }, + /** + * @param {{ groupId: string }} params + * @return { Promise<{json: any, params}> } + */ + leaveGroup(params) { + return window.API.call(`groups/${params.groupId}/leave`, { + method: 'POST' + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + /** + * @param {{ query: string }} params + * @return { Promise<{json: any, params}> } + */ + groupStrictsearch(params) { + return window.API.call(`groups/strictsearch`, { + method: 'GET', + params + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + /** + userId: string, + groupId: string, + params: { + visibility: string, + isSubscribedToAnnouncements: bool, + managerNotes: string + } + */ + setGroupMemberProps(userId, groupId, params) { + return window.API.call(`groups/${groupId}/members/${userId}`, { + method: 'PUT', + params + }).then((json) => { + const args = { + json, + userId, + groupId, + params + }; + window.API.$emit('GROUP:MEMBER:PROPS', args); + return args; + }); + }, + /** + * @param {{ + * userId: string, + * groupId: string, + * roleId: string + * }} params + * @return { Promise<{json: any, params}> } + */ + addGroupMemberRole(params) { + return window.API.call( + `groups/${params.groupId}/members/${params.userId}/roles/${params.roleId}`, + { + method: 'PUT' + } + ).then((json) => { + const args = { + json, + params + }; + // window.API.$emit('GROUP:MEMBER:ROLE:CHANGE', args); + return args; + }); + }, + /** + * @param {{ + * userId: string, + * groupId: string, + * roleId: string + * }} params + * @return { Promise<{json: any, params}> } + */ + removeGroupMemberRole(params) { + return window.API.call( + `groups/${params.groupId}/members/${params.userId}/roles/${params.roleId}`, + { + method: 'DELETE' + } + ).then((json) => { + const args = { + json, + params + }; + // window.API.$emit('GROUP:MEMBER:ROLE:CHANGE', args); + return args; + }); + }, + getGroupPermissions(params) { + return window.API.call(`users/${params.userId}/groups/permissions`, { + method: 'GET' + }).then((json) => { + const args = { + json, + params + }; + window.API.$emit('GROUP:PERMISSIONS', args); + return args; + }); + }, + /** + * @param {{ + groupId: string, + n: number, + offset: number + }} params + * @return { Promise<{json: any, params}> } + */ + getGroupPosts(params) { + return window.API.call(`groups/${params.groupId}/posts`, { + method: 'GET', + params + }).then((json) => { + const args = { + json, + params + }; + window.API.$emit('GROUP:POSTS', args); + return args; + }); + }, + editGroupPost(params) { + return window.API.call( + `groups/${params.groupId}/posts/${params.postId}`, + { + method: 'PUT', + params + } + ).then((json) => { + const args = { + json, + params + }; + window.API.$emit('GROUP:POST', args); + return args; + }); + }, + createGroupPost(params) { + return window.API.call(`groups/${params.groupId}/posts`, { + method: 'POST', + params + }).then((json) => { + const args = { + json, + params + }; + window.API.$emit('GROUP:POST', args); + return args; + }); + }, + /** + * @param {{ + * groupId: string, + * userId: string + * }} params + * @return { Promise<{json: any, params}> } + */ + getGroupMember(params) { + return window.API.call( + `groups/${params.groupId}/members/${params.userId}`, + { + method: 'GET' + } + ).then((json) => { + const args = { + json, + params + }; + // window.API.$emit('GROUP:MEMBER', args); + return args; + }); + }, + /** + * @param {{ + * groupId: string, + * n: number, + * offset: number + * }} params + * @return { Promise<{json: any, params}> } + */ + getGroupMembers(params) { + return window.API.call(`groups/${params.groupId}/members`, { + method: 'GET', + params + }).then((json) => { + const args = { + json, + params + }; + window.API.$emit('GROUP:MEMBERS', args); + return args; + }); + }, + /** + * @param {{ + * groupId: string, + * query: string, + * n: number, + * offset: number + * }} params + * @return { Promise<{json: any, params}> } + */ + getGroupMembersSearch(params) { + return window.API.call(`groups/${params.groupId}/members/search`, { + method: 'GET', + params + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + /** + * @param {{ + * groupId: string + * }} params + * @return { Promise<{json: any, params}> } + */ + blockGroup(params) { + return window.API.call(`groups/${params.groupId}/block`, { + method: 'POST' + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + /** + * @param {{ + * groupId: string, + * userId: string + * }} params + * @return { Promise<{json: any, params}> } + */ + unblockGroup(params) { + return window.API.call( + `groups/${params.groupId}/members/${params.userId}`, + { + method: 'DELETE' + } + ).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + /** + * @param {{ + * groupId: string, + * userId: string + * }} params + * @return { Promise<{json: any, params}> } + */ + sendGroupInvite(params) { + return window.API.call(`groups/${params.groupId}/invites`, { + method: 'POST', + params: { + userId: params.userId + } + }).then((json) => { + const args = { + json, + params + }; + window.API.$emit('GROUP:INVITE', args); + return args; + }); + }, + /** + * @param {{ + * groupId: string, + * userId: string + * }} params + * @return { Promise<{json: any, params}> } + */ + kickGroupMember(params) { + return window.API.call( + `groups/${params.groupId}/members/${params.userId}`, + { + method: 'DELETE' + } + ).then((json) => { + const args = { + json, + params + }; + // useless code + // window.API.$emit('GROUP:MEMBER:KICK', args); + return args; + }); + }, + /** + * @param {{ groupId: string, userId: string }} params + * @return { Promise<{json: any, params}> } + */ + banGroupMember(params) { + return window.API.call(`groups/${params.groupId}/bans`, { + method: 'POST', + params: { + userId: params.userId + } + }).then((json) => { + const args = { + json, + params + }; + // useless code + // window.API.$emit('GROUP:MEMBER:BAN', args); + return args; + }); + }, + unbanGroupMember(params) { + return window.API.call( + `groups/${params.groupId}/bans/${params.userId}`, + { + method: 'DELETE' + } + ).then((json) => { + const args = { + json, + params + }; + // useless code + // window.API.$emit('GROUP:MEMBER:UNBAN', args); + return args; + }); + }, + /** + * @param {{ groupId: string, userId: string }} params + * @return { Promise<{json: any, params}> } + */ + deleteSentGroupInvite(params) { + return window.API.call( + `groups/${params.groupId}/invites/${params.userId}`, + { + method: 'DELETE' + } + ).then((json) => { + const args = { + json, + params + }; + // useless code + // window.API.$emit('GROUP:INVITE:DELETE', args); + return args; + }); + }, + deleteBlockedGroupRequest(params) { + return window.API.call( + `groups/${params.groupId}/members/${params.userId}`, + { + method: 'DELETE' + } + ).then((json) => { + const args = { + json, + params + }; + // useless code + // window.API.$emit('GROUP:BLOCKED:DELETE', args); + return args; + }); + }, + acceptGroupInviteRequest(params) { + return window.API.call( + `groups/${params.groupId}/requests/${params.userId}`, + { + method: 'PUT', + params: { + action: 'accept' + } + } + ).then((json) => { + const args = { + json, + params + }; + // useless code + // window.API.$emit('GROUP:INVITE:ACCEPT', args); + return args; + }); + }, + rejectGroupInviteRequest(params) { + return window.API.call( + `groups/${params.groupId}/requests/${params.userId}`, + { + method: 'PUT', + params: { + action: 'reject' + } + } + ).then((json) => { + const args = { + json, + params + }; + // useless code + // window.API.$emit('GROUP:INVITE:REJECT', args); + return args; + }); + }, + blockGroupInviteRequest(params) { + return window.API.call( + `groups/${params.groupId}/requests/${params.userId}`, + { + method: 'PUT', + params: { + action: 'reject', + block: true + } + } + ).then((json) => { + const args = { + json, + params + }; + // useless code + // window.API.$emit('GROUP:INVITE:BLOCK', args); + return args; + }); + }, + getGroupBans(params) { + return window.API.call(`groups/${params.groupId}/bans`, { + method: 'GET', + params + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + /** + * @param {{ groupId: string }} params + * @return { Promise<{json: any, params}> } + */ + getGroupAuditLogTypes(params) { + return window.API.call(`groups/${params.groupId}/auditLogTypes`, { + method: 'GET' + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + /** + * @param {{ groupId: string, eventTypes: array }} params + * @return { Promise<{json: any, params}> } + */ + getGroupLogs(params) { + return window.API.call(`groups/${params.groupId}/auditLogs`, { + method: 'GET', + params + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + /** + * @param {{ groupId: string }} params + * @return { Promise<{json: any, params}> } + */ + getGroupInvites(params) { + return window.API.call(`groups/${params.groupId}/invites`, { + method: 'GET', + params + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + /** + * @param {{ groupId: string }} params + * @return { Promise<{json: any, params}> } + */ + getGroupJoinRequests(params) { + return window.API.call(`groups/${params.groupId}/requests`, { + method: 'GET', + params + }).then((json) => { + const args = { + json, + params + }; + // window.API.$emit('GROUP:JOINREQUESTS', args); + return args; + }); + }, + /** + * @param {{ groupId: string }} params + * @return { Promise<{json: any, params}> } + */ + getGroupInstances(params) { + return window.API.call( + `users/${window.API.currentUser.id}/instances/groups/${params.groupId}`, + { + method: 'GET' + } + ).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + /** + * @param {{ groupId: string }} params + * @return { Promise<{json: any, params}> } + */ + getGroupRoles(params) { + return window.API.call(`groups/${params.groupId}/roles`, { + method: 'GET', + params + }).then((json) => { + const args = { + json, + params + }; + // useless code + // this.$emit('GROUP:ROLES', args); + return args; + }); + }, + getUsersGroupInstances() { + return window.API.call( + `users/${window.API.currentUser.id}/instances/groups`, + { + method: 'GET' + } + ).then((json) => { + const args = { + json + }; + window.API.$emit('GROUP:USER:INSTANCES', args); + return args; + }); + }, + + /** + * @param {{ + query: string, + n: number, + offset: number, + order: string, + sortBy: string + }} params + * @return { Promise<{json: any, params}> } + */ + groupSearch(params) { + return window.API.call(`groups`, { + method: 'GET', + params + }).then((json) => { + var args = { + json, + params + }; + return args; + }); + }, + /** + * @param {{ + groupId: string, + galleryId: string, + n: number, + offset: number + }} params + * @return { Promise<{json: any, params}> } + */ + getGroupGallery(params) { + return window.API.call( + `groups/${params.groupId}/galleries/${params.galleryId}`, + { + method: 'GET', + params: { + n: params.n, + offset: params.offset + } + } + ).then((json) => { + const args = { + json, + params + }; + return args; + }); + } + + // no place to use this + // getRequestedGroups() { + // return window.API.call( + // `users/${window.API.currentUser.id}/groups/requested`, + // { + // method: 'GET' + // } + // ).then((json) => { + // const args = { + // json + // }; + // window.API.$emit('GROUP:REQUESTED', args); + // return args; + // }); + // } + + // ----------------- left over code ----------------- + // /** + // * @param {{ groupId: string }} params + // * @return { Promise<{json: any, params}> } + // */ + // 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; + // }); + // }; +}; + +export default groupReq; diff --git a/src/classes/request/index.js b/src/classes/request/index.js index b7bc2695..4928f549 100644 --- a/src/classes/request/index.js +++ b/src/classes/request/index.js @@ -20,6 +20,7 @@ import vrcPlusImageRequest from './vrcPlusImage'; import inviteMessagesRequest from './inviteMessages'; import imageRequest from './image'; import miscRequest from './misc'; +import groupRequest from './group'; window.request = { userRequest, @@ -35,7 +36,8 @@ window.request = { vrcPlusImageRequest, inviteMessagesRequest, imageRequest, - miscRequest + miscRequest, + groupRequest }; export { @@ -52,5 +54,6 @@ export { vrcPlusImageRequest, inviteMessagesRequest, imageRequest, - miscRequest + miscRequest, + groupRequest }; diff --git a/src/classes/sharedFeed.js b/src/classes/sharedFeed.js index 554e1429..9503a952 100644 --- a/src/classes/sharedFeed.js +++ b/src/classes/sharedFeed.js @@ -1,7 +1,7 @@ import * as workerTimers from 'worker-timers'; import configRepository from '../repository/config.js'; -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; -import { worldRequest } from './request'; +import { baseClass, $app, API } from './baseClass.js'; +import { worldRequest, groupRequest } from './request'; export default class extends baseClass { constructor(_app, _API, _t) { @@ -121,13 +121,15 @@ export default class extends baseClass { groupName = groupRef.name; } else { // no group cache, fetch group and try again - API.getGroup({ - groupId: ref.$location.groupId - }) + groupRequest + .getGroup({ + groupId: ref.$location.groupId + }) .then((args) => { workerTimers.setTimeout(() => { // delay to allow for group cache to update - $app.sharedFeed.pendingUpdate = true; + $app.sharedFeed.pendingUpdate = + true; $app.updateSharedFeed(false); }, 100); return args; diff --git a/src/classes/uiComponents.js b/src/classes/uiComponents.js index 972754f2..2c457500 100644 --- a/src/classes/uiComponents.js +++ b/src/classes/uiComponents.js @@ -169,7 +169,7 @@ export default class extends baseClass { if (!L.groupId) { return; } - API.$emit('SHOW_GROUP_DIALOG', L.groupId); + this.showGroupDialog(L.groupId); } }, watch: { @@ -320,7 +320,7 @@ export default class extends baseClass { // check group perms var groupId = this.instance.ownerId; var group = API.cachedGroups.get(groupId); - this.canCloseInstance = $app.hasGroupPermission( + this.canCloseInstance = utils.hasGroupPermission( group, 'group-instance-moderate' ); @@ -339,7 +339,7 @@ export default class extends baseClass { } }, showUserDialog(userId) { - API.$emit('SHOW_USER_DIALOG', userId); + this.showUserDialog(userId); } }, watch: { diff --git a/src/classes/updateLoop.js b/src/classes/updateLoop.js index 1e48a7be..6c03c63a 100644 --- a/src/classes/updateLoop.js +++ b/src/classes/updateLoop.js @@ -1,5 +1,6 @@ import * as workerTimers from 'worker-timers'; -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; +import { baseClass, $app, API } from './baseClass.js'; +import { groupRequest } from './request/index.js'; export default class extends baseClass { constructor(_app, _API, _t) { @@ -47,7 +48,7 @@ export default class extends baseClass { if (--this.nextGroupInstanceRefresh <= 0) { if (this.friendLogInitStatus) { this.nextGroupInstanceRefresh = 300; // 5min - API.getUsersGroupInstances(); + groupRequest.getUsersGroupInstances(); } AppApi.CheckGameRunning(); } diff --git a/src/classes/utils.js b/src/classes/utils.js index 4dc0dccb..29454691 100644 --- a/src/classes/utils.js +++ b/src/classes/utils.js @@ -448,5 +448,46 @@ export default { return `https://vrchat.com/home/launch?worldId=${encodeURIComponent( L.worldId )}`; + }, + getFaviconUrl(resource) { + try { + const url = new URL(resource); + return `https://icons.duckduckgo.com/ip2/${url.host}.ico`; + } catch (err) { + return ''; + } + }, + copyToClipboard(text) { + navigator.clipboard + .writeText(text) + .then(() => { + window.$app.$message({ + message: 'Copied successfully!', + type: 'success' + }); + }) + .catch((err) => { + console.error('Copy failed:', err); + this.$message.error('Copy failed!'); + }); + }, + hasGroupPermission(ref, permission) { + if ( + ref && + ref.myMember && + ref.myMember.permissions && + (ref.myMember.permissions.includes('*') || + ref.myMember.permissions.includes(permission)) + ) { + return true; + } + return false; + }, + getAuditLogTypeName(auditLogType) { + if (!auditLogType) return ''; + return auditLogType + .replace('group.', '') + .replace(/\./g, ' ') + .replace(/\b\w/g, (l) => l.toUpperCase()); } }; diff --git a/src/classes/websocket.js b/src/classes/websocket.js index de8ff06b..63e00f9b 100644 --- a/src/classes/websocket.js +++ b/src/classes/websocket.js @@ -1,6 +1,7 @@ import * as workerTimers from 'worker-timers'; import Noty from 'noty'; -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; +import { baseClass, $app, API, $utils } from './baseClass.js'; +import { groupRequest } from './request'; export default class extends baseClass { constructor(_app, _API, _t) { @@ -450,7 +451,7 @@ export default class extends baseClass { case 'group-role-updated': var groupId = content.role.groupId; - API.getGroup({ groupId, includeRoles: true }); + groupRequest.getGroup({ groupId, includeRoles: true }); console.log('group-role-updated', content); // content { diff --git a/src/components/common/Location.vue b/src/components/common/Location.vue index 380020a9..1577f816 100644 --- a/src/components/common/Location.vue +++ b/src/components/common/Location.vue @@ -153,7 +153,7 @@ if (!L.groupId) { return; } - this.API.$emit('SHOW_GROUP_DIALOG', L.groupId); + this.showGroupDialog(L.groupId); } } }; diff --git a/src/components/favorites/FavoritesWorldTab.vue b/src/components/favorites/FavoritesWorldTab.vue index fc19b956..7bc000e2 100644 --- a/src/components/favorites/FavoritesWorldTab.vue +++ b/src/components/favorites/FavoritesWorldTab.vue @@ -353,7 +353,7 @@ type: 'info', callback: (action) => { if (action === 'confirm') { - this.deleteLocalWorldFavoriteGroup(group); + this.$emit('delete-local-world-favorite-group', group); } } }); diff --git a/src/composables/groups/useGroupMemberModeration.js b/src/composables/groups/useGroupMemberModeration.js new file mode 100644 index 00000000..0c8e57c0 --- /dev/null +++ b/src/composables/groups/useGroupMemberModeration.js @@ -0,0 +1,164 @@ +import { reactive, ref } from 'vue'; +import configRepository from '../../repository/config'; + +function useModerationTable() { + const groupInvitesModerationTable = reactive({ + data: [], + tableProps: { stripe: true, size: 'mini' }, + pageSize: 15, + paginationProps: { + small: true, + layout: 'sizes,prev,pager,next,total', + pageSizes: [10, 15, 25, 50, 100] + } + }); + const groupJoinRequestsModerationTable = reactive({ + data: [], + tableProps: { stripe: true, size: 'mini' }, + pageSize: 15, + paginationProps: { + small: true, + layout: 'sizes,prev,pager,next,total', + pageSizes: [10, 15, 25, 50, 100] + } + }); + const groupBlockedModerationTable = reactive({ + data: [], + tableProps: { stripe: true, size: 'mini' }, + pageSize: 15, + paginationProps: { + small: true, + layout: 'sizes,prev,pager,next,total', + pageSizes: [10, 15, 25, 50, 100] + } + }); + const groupLogsModerationTable = reactive({ + data: [], + filters: [{ prop: ['description'], value: '' }], + tableProps: { stripe: true, size: 'mini' }, + pageSize: 15, + paginationProps: { + small: true, + layout: 'sizes,prev,pager,next,total', + pageSizes: [10, 15, 25, 50, 100] + } + }); + const groupBansModerationTable = reactive({ + data: [], + filters: [{ prop: ['$displayName'], value: '' }], + tableProps: { stripe: true, size: 'mini' }, + pageSize: 15, + paginationProps: { + small: true, + layout: 'sizes,prev,pager,next,total', + pageSizes: [10, 15, 25, 50, 100] + } + }); + const groupMemberModerationTable = reactive({ + data: [], + tableProps: { stripe: true, size: 'mini' }, + pageSize: 15, + paginationProps: { + small: true, + layout: 'sizes,prev,pager,next,total', + pageSizes: [10, 15, 25, 50, 100] + } + }); + + async function initializePageSize() { + try { + const tablePageSize = await configRepository.getInt( + 'VRCX_tablePageSize', + 15 + ); + groupMemberModerationTable.pageSize = tablePageSize; + groupBansModerationTable.pageSize = tablePageSize; + groupLogsModerationTable.pageSize = tablePageSize; + groupInvitesModerationTable.pageSize = tablePageSize; + groupJoinRequestsModerationTable.pageSize = tablePageSize; + groupBlockedModerationTable.pageSize = tablePageSize; + } catch (error) { + console.error('Failed to initialize table page size:', error); + } + } + + function deselectGroupMember(userId) { + const deselectInTable = (tableData) => { + if (userId) { + const row = tableData.find((item) => item.userId === userId); + if (row) { + row.$selected = false; + } + } else { + tableData.forEach((row) => { + if (row.$selected) { + row.$selected = false; + } + }); + } + }; + + deselectInTable(groupMemberModerationTable.data); + deselectInTable(groupBansModerationTable.data); + deselectInTable(groupInvitesModerationTable.data); + deselectInTable(groupJoinRequestsModerationTable.data); + deselectInTable(groupBlockedModerationTable.data); + } + + return { + groupInvitesModerationTable, + groupJoinRequestsModerationTable, + groupBlockedModerationTable, + groupLogsModerationTable, + groupBansModerationTable, + groupMemberModerationTable, + initializePageSize, + deselectGroupMember + }; +} + +function useSelectedUsers() { + const selectedUsers = reactive({}); + // computed not working here hmm + const selectedUsersArray = ref([]); + + function groupMemberModerationTableSelectionChange(row) { + if (row.$selected && !selectedUsers[row.userId]) { + setSelectedUsers(row.userId, row); + } else if (!row.$selected && selectedUsers[row.userId]) { + deselectedUsers(row.userId); + } + } + + function deselectedUsers(userId, isAll = false) { + if (isAll) { + for (const id in selectedUsers) { + if (Object.prototype.hasOwnProperty.call(selectedUsers, id)) { + delete selectedUsers[id]; + } + } + } else { + if (Object.prototype.hasOwnProperty.call(selectedUsers, userId)) { + delete selectedUsers[userId]; + } + } + selectedUsersArray.value = Object.values(selectedUsers); + } + + function setSelectedUsers(usersId, user) { + if (!user) { + return; + } + selectedUsers[usersId] = user; + selectedUsersArray.value = Object.values(selectedUsers); + } + return { + selectedUsers, + selectedUsersArray, + groupMemberModerationTableSelectionChange, + deselectedUsers, + setSelectedUsers + }; +} + +export { useModerationTable, useSelectedUsers }; diff --git a/src/mixins/dialogs/groupDialog.pug b/src/mixins/dialogs/groupDialog.pug deleted file mode 100644 index a5b8b62d..00000000 --- a/src/mixins/dialogs/groupDialog.pug +++ /dev/null @@ -1,758 +0,0 @@ -mixin groupDialog - el-dialog.x-dialog.x-group-dialog( - :before-close='beforeDialogClose' - @mousedown.native='dialogMouseDown' - @mouseup.native='dialogMouseUp' - ref='groupDialog' - :visible.sync='groupDialog.visible' - :show-close='false' - width='770px' - top='10vh') - .group-banner-image - el-popover(placement='right' width='500px' trigger='click') - img.x-link( - slot='reference' - v-lazy='groupDialog.ref.bannerUrl' - style='flex: none; width: 100%; aspect-ratio: 6/1; object-fit: cover; border-radius: 4px') - img.x-link( - v-lazy='groupDialog.ref.bannerUrl' - style='width: 854px; height: 480px' - @click='showFullscreenImageDialog(groupDialog.ref.bannerUrl)') - .group-body(v-loading='groupDialog.loading') - div(style='display: flex') - el-popover(placement='right' width='500px' trigger='click') - img.x-link( - slot='reference' - v-lazy='groupDialog.ref.iconUrl' - style='flex: none; width: 120px; height: 120px; border-radius: 12px') - img.x-link( - v-lazy='groupDialog.ref.iconUrl' - style='width: 500px; height: 500px' - @click='showFullscreenImageDialog(groupDialog.ref.iconUrl)') - div(style='flex: 1; display: flex; align-items: center; margin-left: 15px') - .group-header(style='flex: 1') - span(v-if='groupDialog.ref.ownerId === API.currentUser.id' style='margin-right: 5px') 👑 - span.dialog-title(v-text='groupDialog.ref.name' style='margin-right: 5px') - span.group-discriminator.x-grey( - style='font-family: monospace; font-size: 12px; margin-right: 5px') {{ groupDialog.ref.shortCode }}.{{ groupDialog.ref.discriminator }} - el-tooltip(v-for='item in groupDialog.ref.$languages' :key='item.key' placement='top') - template(#content) - span {{ item.value }} ({{ item.key }}) - span.flags( - :class='languageClass(item.key)' - style='display: inline-block; margin-right: 5px') - div(style='margin-top: 5px') - span.x-link.x-grey( - v-text='groupDialog.ownerDisplayName' - @click='showUserDialog(groupDialog.ref.ownerId)' - style='font-family: monospace') - .group-tags - el-tag( - v-if='groupDialog.ref.isVerified' - type='info' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.verified') }} - - el-tag( - v-if='groupDialog.ref.privacy === "private"' - type='danger' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.private') }} - el-tag( - v-if='groupDialog.ref.privacy === "default"' - type='success' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.public') }} - - el-tag( - v-if='groupDialog.ref.joinState === "open"' - type='success' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.open') }} - el-tag( - v-else-if='groupDialog.ref.joinState === "request"' - type='warning' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.request') }} - el-tag( - v-else-if='groupDialog.ref.joinState === "invite"' - type='danger' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.invite') }} - el-tag( - v-else-if='groupDialog.ref.joinState === "closed"' - type='danger' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.closed') }} - - el-tag( - v-if='groupDialog.inGroup' - type='info' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.joined') }} - el-tag( - v-if='groupDialog.ref.myMember && groupDialog.ref.myMember.bannedAt' - type='danger' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.banned') }} - - template(v-if='groupDialog.inGroup && groupDialog.ref.myMember') - el-tag( - v-if='groupDialog.ref.myMember.visibility === "visible"' - type='info' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.visible') }} - el-tag( - v-else-if='groupDialog.ref.myMember.visibility === "friends"' - type='info' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.friends') }} - el-tag( - v-else-if='groupDialog.ref.myMember.visibility === "hidden"' - type='info' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.hidden') }} - el-tag( - v-if='groupDialog.ref.myMember.isSubscribedToAnnouncements' - type='info' - effect='plain' - size='mini' - style='margin-right: 5px; margin-top: 5px') {{ $t('dialog.group.tags.subscribed') }} - - .group-description(style='margin-top: 5px') - span( - v-show='groupDialog.ref.name !== groupDialog.ref.description' - v-text='groupDialog.ref.description' - style='font-size: 12px') - div(style='flex: none; margin-left: 10px') - template(v-if='groupDialog.inGroup && groupDialog.ref?.myMember') - el-tooltip( - v-if='groupDialog.ref.myMember?.isRepresenting' - placement='top' - :content='$t("dialog.group.actions.unrepresent_tooltip")' - :disabled='hideTooltips') - el-button( - type='warning' - icon='el-icon-star-on' - circle - @click='clearGroupRepresentation(groupDialog.id)' - style='margin-left: 5px') - el-tooltip( - v-else - placement='top' - :content='$t("dialog.group.actions.represent_tooltip")' - :disabled='hideTooltips') - span - el-button( - type='default' - icon='el-icon-star-off' - circle - @click='setGroupRepresentation(groupDialog.id)' - style='margin-left: 5px' - :disabled='groupDialog.ref.privacy === "private"') - template(v-else-if='groupDialog.ref.myMember?.membershipStatus === "requested"') - el-tooltip( - placement='top' - :content='$t("dialog.group.actions.cancel_join_request_tooltip")' - :disabled='hideTooltips') - span - el-button( - type='default' - icon='el-icon-close' - circle - @click='cancelGroupRequest(groupDialog.id)' - style='margin-left: 5px') - template(v-else-if='groupDialog.ref.myMember?.membershipStatus === "invited"') - el-tooltip( - placement='top' - :content='$t("dialog.group.actions.pending_request_tooltip")' - :disabled='hideTooltips') - span - el-button( - type='default' - icon='el-icon-check' - circle - @click='joinGroup(groupDialog.id)' - style='margin-left: 5px') - template(v-else) - el-tooltip( - v-if='groupDialog.ref.joinState === "request"' - placement='top' - :content='$t("dialog.group.actions.request_join_tooltip")' - :disabled='hideTooltips') - el-button( - type='default' - icon='el-icon-message' - circle - @click='joinGroup(groupDialog.id)' - style='margin-left: 5px') - el-tooltip( - v-if='groupDialog.ref.joinState === "invite"' - placement='top' - :content='$t("dialog.group.actions.invite_required_tooltip")' - :disabled='hideTooltips') - span - el-button( - type='default' - icon='el-icon-message' - disabled - circle - style='margin-left: 5px') - el-tooltip( - v-if='groupDialog.ref.joinState === "open"' - placement='top' - :content='$t("dialog.group.actions.join_group_tooltip")' - :disabled='hideTooltips') - el-button( - type='default' - icon='el-icon-check' - circle - @click='joinGroup(groupDialog.id)' - style='margin-left: 5px') - el-dropdown( - trigger='click' - @command='groupDialogCommand' - size='small' - style='margin-left: 5px') - el-button( - :type='groupDialog.ref.membershipStatus === "userblocked" ? "danger" : "default"' - icon='el-icon-more' - circle) - el-dropdown-menu(#default='dropdown') - el-dropdown-item(icon='el-icon-refresh' command='Refresh') {{ $t('dialog.group.actions.refresh') }} - el-dropdown-item(icon='el-icon-share' command='Share') {{ $t('dialog.group.actions.share') }} - template(v-if='groupDialog.inGroup') - template(v-if='groupDialog.ref.myMember') - el-dropdown-item( - v-if='groupDialog.ref.myMember.isSubscribedToAnnouncements' - icon='el-icon-close' - command='Unsubscribe To Announcements' - divided) {{ $t('dialog.group.actions.unsubscribe') }} - el-dropdown-item( - v-else - icon='el-icon-check' - command='Subscribe To Announcements' - divided) {{ $t('dialog.group.actions.subscribe') }} - el-dropdown-item( - v-if='hasGroupPermission(groupDialog.ref, "group-invites-manage")' - icon='el-icon-message' - command='Invite To Group') {{ $t('dialog.group.actions.invite_to_group') }} - template(v-if='hasGroupPermission(groupDialog.ref, "group-announcement-manage")') - el-dropdown-item(icon='el-icon-tickets' command='Create Post') {{ $t('dialog.group.actions.create_post') }} - //- template(v-if="hasGroupPermission(groupDialog.ref, 'group-members-manage')") - el-dropdown-item(icon='el-icon-s-operation' command='Moderation Tools') {{ $t('dialog.group.actions.moderation_tools') }} - template(v-if='groupDialog.ref.myMember && groupDialog.ref.privacy === "default"') - el-dropdown-item(icon='el-icon-view' command='Visibility Everyone' divided) #[i.el-icon-check(v-if='groupDialog.ref.myMember.visibility === "visible"')] {{ $t('dialog.group.actions.visibility_everyone') }} - el-dropdown-item(icon='el-icon-view' command='Visibility Friends') #[i.el-icon-check(v-if='groupDialog.ref.myMember.visibility === "friends"')] {{ $t('dialog.group.actions.visibility_friends') }} - el-dropdown-item(icon='el-icon-view' command='Visibility Hidden') #[i.el-icon-check(v-if='groupDialog.ref.myMember.visibility === "hidden"')] {{ $t('dialog.group.actions.visibility_hidden') }} - el-dropdown-item( - icon='el-icon-delete' - command='Leave Group' - style='color: #f56c6c' - divided) {{ $t('dialog.group.actions.leave') }} - template(v-else) - el-dropdown-item( - v-if='groupDialog.ref.membershipStatus === "userblocked"' - icon='el-icon-circle-check' - command='Unblock Group' - style='color: #f56c6c' - divided) {{ $t('dialog.group.actions.unblock') }} - el-dropdown-item(v-else icon='el-icon-circle-close' command='Block Group' divided) {{ $t('dialog.group.actions.block') }} - el-tabs(ref='groupDialogTabs' @tab-click='groupDialogTabClick') - el-tab-pane(:label='$t("dialog.group.info.header")') - .group-banner-image-info - el-popover(placement='right' width='500px' trigger='click') - img.x-link( - slot='reference' - v-lazy='groupDialog.ref.bannerUrl' - style='flex: none; width: 100%; aspect-ratio: 6/1; object-fit: cover; border-radius: 4px') - img.x-link( - v-lazy='groupDialog.ref.bannerUrl' - style='width: 854px; height: 480px' - @click='showFullscreenImageDialog(groupDialog.ref.bannerUrl)') - .x-friend-list(style='max-height: none') - span( - v-if='groupDialog.instances.length' - style='font-size: 12px; font-weight: bold; margin: 5px') {{ $t('dialog.group.info.instances') }} - div(v-for='room in groupDialog.instances' :key='room.tag' style='width: 100%') - div(style='margin: 5px 0') - location(:location='room.tag' style='display: inline-block') - el-tooltip(placement='top' content='Invite yourself' :disabled='hideTooltips') - invite-yourself(:location='room.tag' style='margin-left: 5px') - el-tooltip(placement='top' content='Refresh player count' :disabled='hideTooltips') - el-button( - @click='refreshInstancePlayerCount(room.tag)' - size='mini' - icon='el-icon-refresh' - style='margin-left: 5px' - circle) - last-join(:location='room.tag' :currentlocation='lastLocation.location') - instance-info( - :location='room.tag' - :instance='room.ref' - :friendcount='room.friendCount' - :updateelement='updateInstanceInfo') - .x-friend-list( - style='margin: 10px 0; padding: 0; max-height: unset' - v-if='room.users.length') - .x-friend-item.x-friend-item-border( - v-for='user in room.users' - :key='user.id' - @click='showUserDialog(user.id)') - .avatar(:class='userStatusClass(user)') - img(v-lazy='userImage(user)') - .detail - span.name(v-text='user.displayName' :style='{ color: user.$userColour }') - span.extra(v-if='user.location === "traveling"') - i.el-icon-loading(style='margin-right: 5px') - timer(:epoch='user.$travelingToTime') - span.extra(v-else) - timer(:epoch='user.$location_at') - .x-friend-item(style='width: 100%; cursor: default') - .detail - span.name {{ $t('dialog.group.info.announcement') }} - span(style='display: block' v-text='groupDialog.announcement.title') - div( - v-if='groupDialog.announcement.imageUrl' - style='display: inline-block; margin-right: 5px') - el-popover(placement='right' width='500px' trigger='click') - img.x-link( - slot='reference' - v-lazy='groupDialog.announcement.imageUrl' - style='flex: none; width: 60px; height: 60px; border-radius: 4px; object-fit: cover') - img.x-link( - v-lazy='groupDialog.announcement.imageUrl' - style='height: 500px' - @click='showFullscreenImageDialog(groupDialog.announcement.imageUrl)') - 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') - 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 {{ $t('dialog.group.posts.created_at') }} {{ groupDialog.announcement.createdAt | formatDate('long') }} - template( - v-if='groupDialog.announcement.updatedAt !== groupDialog.announcement.createdAt') - br - span {{ $t('dialog.group.posts.edited_at') }} {{ groupDialog.announcement.updatedAt | formatDate('long') }} - timer(:epoch='Date.parse(groupDialog.announcement.updatedAt)') - template(v-if='hasGroupPermission(groupDialog.ref, "group-announcement-manage")') - el-tooltip( - placement='top' - :content='$t("dialog.group.posts.edit_tooltip")' - :disabled='hideTooltips') - el-button( - type='text' - icon='el-icon-edit' - size='mini' - style='margin-left: 5px' - @click='showGroupPostEditDialog(groupDialog.id, groupDialog.announcement)') - el-tooltip( - placement='top' - :content='$t("dialog.group.posts.delete_tooltip")' - :disabled='hideTooltips') - el-button( - type='text' - icon='el-icon-delete' - size='mini' - style='margin-left: 5px' - @click='confirmDeleteGroupPost(groupDialog.announcement)') - .x-friend-item(style='width: 100%; cursor: default') - .detail - span.name {{ $t('dialog.group.info.rules') }} - pre.extra( - style='font-family: inherit; font-size: 12px; white-space: pre-wrap; margin: 0 0.5em 0 0') {{ groupDialog.ref.rules || '-' }} - .x-friend-item(style='cursor: default') - .detail - span.name {{ $t('dialog.group.info.members') }} - .extra {{ groupDialog.ref.memberCount }} ({{ groupDialog.ref.onlineMemberCount }}) - .x-friend-item(style='cursor: default') - .detail - span.name {{ $t('dialog.group.info.created_at') }} - span.extra {{ groupDialog.ref.createdAt | formatDate('long') }} - .x-friend-item(style='cursor: default') - .detail - span.name {{ $t('dialog.group.info.links') }} - div( - v-if='groupDialog.ref.links && groupDialog.ref.links.length > 0' - style='margin-top: 5px') - el-tooltip(v-if='link' v-for='(link, index) in groupDialog.ref.links' :key='index') - template(#content) - span(v-text='link') - img( - :src='getFaviconUrl(link)' - style='width: 16px; height: 16px; vertical-align: middle; margin-right: 5px; cursor: pointer' - @click.stop='openExternalLink(link)') - .extra(v-else) - - .x-friend-item(style='width: 350px; cursor: default') - .detail - span.name {{ $t('dialog.group.info.url') }} - span.extra {{ groupDialog.ref.$url }} - el-tooltip( - placement='top' - :content='$t("dialog.group.info.url_tooltip")' - :disabled='hideTooltips') - el-button( - type='default' - @click='copyGroupUrl(groupDialog.ref.$url)' - size='mini' - icon='el-icon-s-order' - circle - style='margin-left: 5px') - .x-friend-item(style='width: 350px; cursor: default') - .detail - span.name {{ $t('dialog.group.info.id') }} - span.extra {{ groupDialog.id }} - el-tooltip( - placement='top' - :content='$t("dialog.group.info.id_tooltip")' - :disabled='hideTooltips') - el-button( - type='default' - @click='copyGroupId(groupDialog.id)' - size='mini' - icon='el-icon-s-order' - circle - style='margin-left: 5px') - div( - v-if='groupDialog.ref.membershipStatus === "member"' - style='width: 100%; margin-top: 10px; border-top: 1px solid #e4e7ed14') - div(style='width: 100%; display: flex; margin-top: 10px') - .x-friend-item(style='cursor: default') - .detail - span.name {{ $t('dialog.group.info.joined_at') }} - span.extra {{ groupDialog.ref.myMember.joinedAt | formatDate('long') }} - .x-friend-item(style='cursor: default') - .detail - span.name {{ $t('dialog.group.info.roles') }} - span.extra(v-if='groupDialog.memberRoles.length === 0') - - span.extra(v-else) - template(v-for='(role, rIndex) in groupDialog.memberRoles') - el-tooltip(:key='rIndex' placement='top') - template(#content) - span {{ $t('dialog.group.info.role') }} {{ role.name }} - br - span {{ $t('dialog.group.info.role_description') }} {{ role.description }} - br - span(v-if='role.updatedAt') {{ $t('dialog.group.info.role_updated_at') }} {{ role.updatedAt | formatDate('long') }} - span(v-else) {{ $t('dialog.group.info.role_created_at') }} {{ role.createdAt | formatDate('long') }} - br - span {{ $t('dialog.group.info.role_permissions') }} - br - template(v-for='(permission, pIndex) in role.permissions') - span(:key='pIndex') {{ permission }} - br - span {{ role.name }}{{ rIndex < groupDialog.memberRoles.length - 1 ? ', ' : '' }} - el-tab-pane(:label='$t("dialog.group.posts.header")' lazy) - 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') - 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 {{ $t('dialog.group.posts.created_at') }} {{ post.createdAt | formatDate('long') }} - template(v-if='post.updatedAt !== post.createdAt') - br - span {{ $t('dialog.group.posts.edited_at') }} {{ post.updatedAt | formatDate('long') }} - timer(:epoch='Date.parse(post.updatedAt)') - template( - v-if='hasGroupPermission(groupDialog.ref, "group-announcement-manage")') - el-tooltip( - placement='top' - :content='$t("dialog.group.posts.edit_tooltip")' - :disabled='hideTooltips') - el-button( - type='text' - icon='el-icon-edit' - size='mini' - style='margin-left: 5px' - @click='showGroupPostEditDialog(groupDialog.id, post)') - el-tooltip( - placement='top' - :content='$t("dialog.group.posts.delete_tooltip")' - :disabled='hideTooltips') - el-button( - type='text' - icon='el-icon-delete' - size='mini' - style='margin-left: 5px' - @click='confirmDeleteGroupPost(post)') - el-tab-pane(:label='$t("dialog.group.members.header")' lazy) - 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') }} - span(v-else style='font-weight: bold; font-size: 16px') {{ $t('dialog.group.members.friends_only') }} - div(style='margin-top: 10px') - el-button( - type='default' - @click='loadAllGroupMembers' - size='mini' - icon='el-icon-refresh' - :loading='isGroupMembersLoading' - circle) - el-button( - type='default' - @click='downloadAndSaveJson(`${groupDialog.id}_members`, groupDialog.members)' - size='mini' - icon='el-icon-download' - circle - style='margin-left: 5px') - span( - v-if='groupDialog.memberSearch.length' - style='font-size: 14px; margin-left: 5px; margin-right: 5px') {{ groupDialog.memberSearchResults.length }}/{{ groupDialog.ref.memberCount }} - span(v-else style='font-size: 14px; margin-left: 5px; margin-right: 5px') {{ groupDialog.members.length }}/{{ groupDialog.ref.memberCount }} - div( - v-if='hasGroupPermission(groupDialog.ref, "group-members-manage")' - style='float: right') - span(style='margin-right: 5px') {{ $t('dialog.group.members.sort_by') }} - el-dropdown( - @click.native.stop - trigger='click' - size='small' - style='margin-right: 5px' - :disabled='isGroupMembersLoading || groupDialog.memberSearch.length') - el-button(size='mini') - span {{ groupDialog.memberSortOrder.name }} #[i.el-icon-arrow-down.el-icon--right] - el-dropdown-menu(#default='dropdown') - el-dropdown-item( - v-for='item in groupDialogSortingOptions' - :key='item.name' - v-text='item.name' - @click.native='setGroupMemberSortOrder(item)') - span(style='margin-right: 5px') {{ $t('dialog.group.members.filter') }} - el-dropdown( - @click.native.stop - trigger='click' - size='small' - style='margin-right: 5px' - :disabled='isGroupMembersLoading || groupDialog.memberSearch.length') - el-button(size='mini') - span {{ groupDialog.memberFilter.name }} #[i.el-icon-arrow-down.el-icon--right] - el-dropdown-menu(#default='dropdown') - el-dropdown-item( - v-for='item in groupDialogFilterOptions' - :key='item.name' - v-text='item.name' - @click.native='setGroupMemberFilter(item)') - el-dropdown-item( - v-for='item in groupDialog.ref.roles' - :key='item.name' - v-if='!item.defaultRole' - v-text='item.name' - @click.native='setGroupMemberFilter(item)') - el-input( - v-model='groupDialog.memberSearch' - @input='groupMembersSearch' - clearable - size='mini' - :placeholder='$t("dialog.group.members.search")' - style='margin-top: 10px; margin-bottom: 10px') - .x-friend-list( - v-if='groupDialog.memberSearch.length' - v-loading='isGroupMembersLoading' - style='margin-top: 10px; overflow: auto; max-height: 250px; min-width: 130px') - .x-friend-item.x-friend-item-border( - v-for='user in groupDialog.memberSearchResults' - :key='user.id' - @click='showUserDialog(user.userId)') - .avatar - img(v-lazy='userImage(user.user)') - .detail - span.name(v-text='user.user.displayName' :style='{ color: user.user.$userColour }') - span.extra - template(v-if='hasGroupPermission(groupDialog.ref, "group-members-manage")') - el-tooltip( - v-if='user.isRepresenting' - placement='top' - :content='$t("dialog.group.members.representing")') - i.el-icon-collection-tag(style='margin-right: 5px') - el-tooltip(v-if='user.visibility !== "visible"' placement='top') - template(#content) - span {{ $t('dialog.group.members.visibility') }} {{ user.visibility }} - i.el-icon-view(style='margin-right: 5px') - el-tooltip( - v-if='!user.isSubscribedToAnnouncements' - placement='top' - :content='$t("dialog.group.members.unsubscribed_announcements")') - i.el-icon-chat-line-square(style='margin-right: 5px') - el-tooltip(v-if='user.managerNotes' placement='top') - template(#content) - span {{ $t('dialog.group.members.manager_notes') }} - br - span {{ user.managerNotes }} - i.el-icon-edit-outline(style='margin-right: 5px') - template(v-for='roleId in user.roleIds') - span( - v-for='(role, rIndex) in groupDialog.ref.roles' - :key='rIndex' - v-if='role.id === roleId' - v-text='role.name') - span(v-if='user.roleIds.indexOf(roleId) < user.roleIds.length - 1') ,  - ul.infinite-list.x-friend-list( - v-else-if='groupDialog.members.length > 0' - v-infinite-scroll='loadMoreGroupMembers' - style='margin-top: 10px; overflow: auto; max-height: 250px; min-width: 130px') - li.infinite-list-item.x-friend-item.x-friend-item-border( - v-for='user in groupDialog.members' - :key='user.id' - @click='showUserDialog(user.userId)') - .avatar - img(v-lazy='userImage(user.user)') - .detail - span.name(v-text='user.user.displayName' :style='{ color: user.user.$userColour }') - span.extra - template(v-if='hasGroupPermission(groupDialog.ref, "group-members-manage")') - el-tooltip( - v-if='user.isRepresenting' - placement='top' - :content='$t("dialog.group.members.representing")') - i.el-icon-collection-tag(style='margin-right: 5px') - el-tooltip(v-if='user.visibility !== "visible"' placement='top') - template(#content) - span {{ $t('dialog.group.members.visibility') }} {{ user.visibility }} - i.el-icon-view(style='margin-right: 5px') - el-tooltip( - v-if='!user.isSubscribedToAnnouncements' - placement='top' - :content='$t("dialog.group.members.unsubscribed_announcements")') - i.el-icon-chat-line-square(style='margin-right: 5px') - el-tooltip(v-if='user.managerNotes' placement='top') - template(#content) - span {{ $t('dialog.group.members.manager_notes') }} - br - span {{ user.managerNotes }} - i.el-icon-edit-outline(style='margin-right: 5px') - template(v-for='roleId in user.roleIds') - span( - v-for='(role, rIndex) in groupDialog.ref.roles' - :key='rIndex' - v-if='role.id === roleId' - v-text='role.name') - span(v-if='user.roleIds.indexOf(roleId) < user.roleIds.length - 1') ,  - .x-friend-item( - v-if='!isGroupMembersDone' - v-loading='isGroupMembersLoading' - style='width: 100%; height: 45px; text-align: center' - @click='loadMoreGroupMembers') - .detail(v-if='!isGroupMembersLoading') - span.name {{ $t('dialog.group.members.load_more') }} - el-tab-pane(:label='$t("dialog.group.gallery.header")' lazy) - el-button( - type='default' - size='mini' - icon='el-icon-refresh' - @click='getGroupGalleries' - :loading='isGroupGalleryLoading' - circle) - 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') - span(v-text='gallery.name' style='font-weight: bold; font-size: 16px') - i.x-status-icon(style='margin-left: 5px' :class='groupGalleryStatus(gallery)') - span(style='color: #909399; font-size: 12px; margin-left: 5px') {{ groupDialog.galleries[gallery.id] ? groupDialog.galleries[gallery.id].length : 0 }} - span(v-text='gallery.description' style='color: #c7c7c7; padding: 10px') - el-carousel(:interval='0' height='600px' style='margin-top: 10px') - el-carousel-item( - v-for='image in groupDialog.galleries[gallery.id]' - :key='image.id') - el-popover(placement='top' width='700px' trigger='click') - img.x-link( - slot='reference' - v-lazy='image.imageUrl' - style='width: 100%; height: 100%; object-fit: contain') - img.x-link( - v-lazy='image.imageUrl' - style='height: 700px' - @click='showFullscreenImageDialog(image.imageUrl)') - el-tab-pane(:label='$t("dialog.group.json.header")' lazy) - el-button( - type='default' - @click='refreshGroupDialogTreeData()' - size='mini' - icon='el-icon-refresh' - circle) - el-button( - type='default' - @click='downloadAndSaveJson(groupDialog.id, groupDialog.ref)' - size='mini' - icon='el-icon-download' - circle - style='margin-left: 5px') - el-tree(:data='groupDialog.treeData' style='margin-top: 5px; font-size: 12px') - template(#default='scope') - span - span(v-text='scope.data.key' style='font-weight: bold; margin-right: 5px') - span(v-if='!scope.data.children' v-text='scope.data.value') diff --git a/src/mixins/dialogs/groups.pug b/src/mixins/dialogs/groups.pug deleted file mode 100644 index ea949da2..00000000 --- a/src/mixins/dialogs/groups.pug +++ /dev/null @@ -1,743 +0,0 @@ -mixin groups - //- dialog: invite group - el-dialog.x-dialog( - :before-close='beforeDialogClose' - @mousedown.native='dialogMouseDown' - @mouseup.native='dialogMouseUp' - ref='inviteGroupDialog' - :visible.sync='inviteGroupDialog.visible' - :title='$t("dialog.invite_to_group.header")' - width='450px') - div(v-if='inviteGroupDialog.visible' v-loading='inviteGroupDialog.loading') - span {{ $t('dialog.invite_to_group.description') }} - br - el-select( - v-model='inviteGroupDialog.groupId' - clearable - :placeholder='$t("dialog.invite_to_group.choose_group_placeholder")' - filterable - :disabled='inviteGroupDialog.loading' - @change='isAllowedToInviteToGroup' - style='margin-top: 15px') - el-option-group( - v-if='API.currentUserGroups.size' - :label='$t("dialog.invite_to_group.groups")' - style='width: 410px') - el-option.x-friend-item( - v-for='group in API.currentUserGroups.values()' - :key='group.id' - :label='group.name' - :value='group.id' - style='height: auto') - .avatar - img(v-lazy='group.iconUrl') - .detail - span.name(v-text='group.name') - el-select( - v-model='inviteGroupDialog.userIds' - multiple - clearable - :placeholder='$t("dialog.invite_to_group.choose_friends_placeholder")' - filterable - :disabled='inviteGroupDialog.loading' - style='width: 100%; margin-top: 15px') - el-option-group(v-if='inviteGroupDialog.userId' :label='$t("dialog.invite_to_group.selected_users")') - el-option.x-friend-item( - :key='inviteGroupDialog.userObject.id' - :label='inviteGroupDialog.userObject.displayName' - :value='inviteGroupDialog.userObject.id' - style='height: auto') - template(v-if='inviteGroupDialog.userObject.id') - .avatar(:class='userStatusClass(inviteGroupDialog.userObject)') - img(v-lazy='userImage(inviteGroupDialog.userObject)') - .detail - span.name( - v-text='inviteGroupDialog.userObject.displayName' - :style='{ color: inviteGroupDialog.userObject.$userColour }') - span(v-else v-text='inviteGroupDialog.userId') - el-option-group(v-if='vipFriends.length' :label='$t("side_panel.favorite")') - el-option.x-friend-item( - v-for='friend in vipFriends' - :key='friend.id' - :label='friend.name' - :value='friend.id' - style='height: auto') - template(v-if='friend.ref') - .avatar(:class='userStatusClass(friend.ref)') - img(v-lazy='userImage(friend.ref)') - .detail - span.name(v-text='friend.ref.displayName' :style='{ color: friend.ref.$userColour }') - span(v-else v-text='friend.id') - el-option-group(v-if='onlineFriends.length' :label='$t("side_panel.online")') - el-option.x-friend-item( - v-for='friend in onlineFriends' - :key='friend.id' - :label='friend.name' - :value='friend.id' - style='height: auto') - template(v-if='friend.ref') - .avatar(:class='userStatusClass(friend.ref)') - img(v-lazy='userImage(friend.ref)') - .detail - span.name(v-text='friend.ref.displayName' :style='{ color: friend.ref.$userColour }') - span(v-else v-text='friend.id') - el-option-group(v-if='activeFriends.length' :label='$t("side_panel.active")') - el-option.x-friend-item( - v-for='friend in activeFriends' - :key='friend.id' - :label='friend.name' - :value='friend.id' - style='height: auto') - template(v-if='friend.ref') - .avatar - img(v-lazy='userImage(friend.ref)') - .detail - span.name(v-text='friend.ref.displayName' :style='{ color: friend.ref.$userColour }') - span(v-else v-text='friend.id') - el-option-group(v-if='offlineFriends.length' :label='$t("side_panel.offline")') - el-option.x-friend-item( - v-for='friend in offlineFriends' - :key='friend.id' - :label='friend.name' - :value='friend.id' - style='height: auto') - template(v-if='friend.ref') - .avatar - img(v-lazy='userImage(friend.ref)') - .detail - span.name(v-text='friend.ref.displayName' :style='{ color: friend.ref.$userColour }') - span(v-else v-text='friend.id') - template(#footer) - el-button( - type='primary' - size='small' - :disabled='inviteGroupDialog.loading || !inviteGroupDialog.userIds.length' - @click='sendGroupInvite()') Invite - - //- dialog: group moderation - el-dialog.x-dialog( - :before-close='beforeDialogClose' - @mousedown.native='dialogMouseDown' - @mouseup.native='dialogMouseUp' - ref='groupMemberModeration' - :visible.sync='groupMemberModeration.visible' - :title='$t("dialog.group_member_moderation.header")' - width='90vw') - div(v-if='groupMemberModeration.visible') - h3(v-text='groupMemberModeration.groupRef.name') - el-tabs(type='card' style='height: 100%') - el-tab-pane(:label='$t("dialog.group_member_moderation.members")') - div(style='margin-top: 10px') - el-button( - type='default' - @click='loadAllGroupMembers' - size='mini' - icon='el-icon-refresh' - :loading='isGroupMembersLoading' - circle) - span(style='font-size: 14px; margin-left: 5px; margin-right: 5px') {{ groupMemberModerationTable.data.length }}/{{ groupMemberModeration.groupRef.memberCount }} - div(style='float: right; margin-top: 5px') - span(style='margin-right: 5px') {{ $t('dialog.group.members.sort_by') }} - el-dropdown( - @click.native.stop - trigger='click' - size='small' - style='margin-right: 5px' - :disabled='isGroupMembersLoading || groupDialog.memberSearch.length || !hasGroupPermission(groupDialog.ref, "group-bans-manage")') - el-button(size='mini') - span {{ groupDialog.memberSortOrder.name }} #[i.el-icon-arrow-down.el-icon--right] - el-dropdown-menu(#default='dropdown') - el-dropdown-item( - v-for='item in groupDialogSortingOptions' - :key='item.name' - v-text='item.name' - @click.native='setGroupMemberSortOrder(item)') - span(style='margin-right: 5px') {{ $t('dialog.group.members.filter') }} - el-dropdown( - @click.native.stop - trigger='click' - size='small' - style='margin-right: 5px' - :disabled='isGroupMembersLoading || groupDialog.memberSearch.length || !hasGroupPermission(groupDialog.ref, "group-bans-manage")') - el-button(size='mini') - span {{ groupDialog.memberFilter.name }} #[i.el-icon-arrow-down.el-icon--right] - el-dropdown-menu(#default='dropdown') - el-dropdown-item( - v-for='item in groupDialogFilterOptions' - :key='item.name' - v-text='item.name' - @click.native='setGroupMemberFilter(item)') - el-dropdown-item( - v-for='item in groupDialog.ref.roles' - :key='item.name' - v-if='!item.defaultRole' - v-text='item.name' - @click.native='setGroupMemberFilter(item)') - el-input( - v-model='groupDialog.memberSearch' - :disabled='!hasGroupPermission(groupDialog.ref, "group-bans-manage")' - @input='groupMembersSearch' - clearable - size='mini' - :placeholder='$t("dialog.group.members.search")' - style='margin-top: 10px; margin-bottom: 10px') - br - el-button(size='small' @click='selectAllGroupMembers') {{ $t('dialog.group_member_moderation.select_all') }} - data-tables(v-bind='groupMemberModerationTable' style='margin-top: 10px') - el-table-column(width='55' prop='$selected' :key='groupMemberModerationTableForceUpdate') - template(#default='scope') - el-button(type='text' size='mini' @click.stop) - el-checkbox( - v-model='scope.row.$selected' - @change='groupMemberModerationTableSelectionChange(scope.row)') - el-table-column(:label='$t("dialog.group_member_moderation.avatar")' width='70' prop='photo') - template(#default='scope') - el-popover(placement='right' height='500px' trigger='hover') - img.friends-list-avatar(slot='reference' v-lazy='userImage(scope.row.user)') - img.friends-list-avatar( - v-lazy='userImageFull(scope.row.user)' - style='height: 500px; cursor: pointer' - @click='showFullscreenImageDialog(userImageFull(scope.row.user))') - el-table-column( - :label='$t("dialog.group_member_moderation.display_name")' - width='160' - prop='$displayName' - sortable) - template(#default='scope') - span(style='cursor: pointer' @click='showUserDialog(scope.row.userId)') - span( - v-if='randomUserColours' - v-text='scope.row.user.displayName' - :style='{ color: scope.row.user.$userColour }') - span(v-else v-text='scope.row.user.displayName') - el-table-column(:label='$t("dialog.group_member_moderation.roles")' prop='roleIds' sortable) - template(#default='scope') - template(v-for='roleId in scope.row.roleIds') - span( - v-for='(role, rIndex) in groupMemberModeration.groupRef.roles' - :key='rIndex' - v-if='role.id === roleId' - v-text='role.name') - span(v-if='scope.row.roleIds.indexOf(roleId) < scope.row.roleIds.length - 1') ,  - el-table-column( - :label='$t("dialog.group_member_moderation.notes")' - prop='managerNotes' - sortable) - template(#default='scope') - span(v-text='scope.row.managerNotes' @click.stop) - el-table-column( - :label='$t("dialog.group_member_moderation.joined_at")' - width='170' - prop='joinedAt' - sortable) - template(#default='scope') - span {{ scope.row.joinedAt | formatDate('long') }} - el-table-column( - :label='$t("dialog.group_member_moderation.visibility")' - width='120' - prop='visibility' - sortable) - template(#default='scope') - span(v-text='scope.row.visibility') - el-tab-pane( - :label='$t("dialog.group_member_moderation.bans")' - :disabled='!hasGroupPermission(groupDialog.ref, "group-bans-manage")') - div(style='margin-top: 10px') - el-button( - type='default' - @click='getAllGroupBans(groupMemberModeration.id)' - size='mini' - icon='el-icon-refresh' - :loading='isGroupMembersLoading' - circle) - span(style='font-size: 14px; margin-left: 5px; margin-right: 5px') {{ groupBansModerationTable.data.length }} - br - el-input( - v-model='groupBansModerationTable.filters[0].value' - clearable - size='mini' - :placeholder='$t("dialog.group.members.search")' - style='margin-top: 10px; margin-bottom: 10px') - br - el-button(size='small' @click='selectAllGroupBans') {{ $t('dialog.group_member_moderation.select_all') }} - data-tables(v-bind='groupBansModerationTable' style='margin-top: 10px') - el-table-column(width='55' prop='$selected' :key='groupMemberModerationTableForceUpdate') - template(#default='scope') - el-button(type='text' size='mini' @click.stop) - el-checkbox( - v-model='scope.row.$selected' - @change='groupMemberModerationTableSelectionChange(scope.row)') - el-table-column(:label='$t("dialog.group_member_moderation.avatar")' width='70' prop='photo') - template(#default='scope') - el-popover(placement='right' height='500px' trigger='hover') - img.friends-list-avatar(slot='reference' v-lazy='userImage(scope.row.user)') - img.friends-list-avatar( - v-lazy='userImageFull(scope.row.user)' - style='height: 500px; cursor: pointer' - @click='showFullscreenImageDialog(userImageFull(scope.row.user))') - el-table-column( - :label='$t("dialog.group_member_moderation.display_name")' - width='160' - prop='$displayName' - sortable) - template(#default='scope') - span(style='cursor: pointer' @click='showUserDialog(scope.row.userId)') - span( - v-if='randomUserColours' - v-text='scope.row.user.displayName' - :style='{ color: scope.row.user.$userColour }') - span(v-else v-text='scope.row.user.displayName') - el-table-column(:label='$t("dialog.group_member_moderation.roles")' prop='roleIds' sortable) - template(#default='scope') - template(v-for='roleId in scope.row.roleIds') - span( - v-for='(role, rIndex) in groupMemberModeration.groupRef.roles' - :key='rIndex' - v-if='role.id === roleId' - v-text='role.name') - span(v-if='scope.row.roleIds.indexOf(roleId) < scope.row.roleIds.length - 1') ,  - el-table-column( - :label='$t("dialog.group_member_moderation.notes")' - prop='managerNotes' - sortable) - template(#default='scope') - span(v-text='scope.row.managerNotes' @click.stop) - el-table-column( - :label='$t("dialog.group_member_moderation.joined_at")' - width='170' - prop='joinedAt' - sortable) - template(#default='scope') - span {{ scope.row.joinedAt | formatDate('long') }} - el-table-column( - :label='$t("dialog.group_member_moderation.banned_at")' - width='170' - prop='joinedAt' - sortable) - template(#default='scope') - span {{ scope.row.bannedAt | formatDate('long') }} - el-tab-pane( - :label='$t("dialog.group_member_moderation.invites")' - :disabled='!hasGroupPermission(groupDialog.ref, "group-invites-manage")') - div(style='margin-top: 10px') - el-button( - type='default' - @click='getAllGroupInvitesAndJoinRequests(groupMemberModeration.id)' - size='mini' - icon='el-icon-refresh' - :loading='isGroupMembersLoading' - circle) - br - el-tabs - el-tab-pane - span(slot='label') - span( - v-text='$t("dialog.group_member_moderation.sent_invites")' - style='font-weight: bold; font-size: 16px') - span(style='color: #909399; font-size: 12px; margin-left: 5px') {{ groupInvitesModerationTable.data.length }} - el-button(size='small' @click='selectAllGroupInvites') {{ $t('dialog.group_member_moderation.select_all') }} - data-tables(v-bind='groupInvitesModerationTable' style='margin-top: 10px') - el-table-column( - width='55' - prop='$selected' - :key='groupMemberModerationTableForceUpdate') - template(#default='scope') - el-button(type='text' size='mini' @click.stop) - el-checkbox( - v-model='scope.row.$selected' - @change='groupMemberModerationTableSelectionChange(scope.row)') - el-table-column( - :label='$t("dialog.group_member_moderation.avatar")' - width='70' - prop='photo') - template(#default='scope') - el-popover(placement='right' height='500px' trigger='hover') - img.friends-list-avatar( - slot='reference' - v-lazy='userImage(scope.row.user)') - img.friends-list-avatar( - v-lazy='userImageFull(scope.row.user)' - style='height: 500px; cursor: pointer' - @click='showFullscreenImageDialog(userImageFull(scope.row.user))') - el-table-column( - :label='$t("dialog.group_member_moderation.display_name")' - width='160' - prop='$displayName' - sortable) - template(#default='scope') - span(style='cursor: pointer' @click='showUserDialog(scope.row.userId)') - span( - v-if='randomUserColours' - v-text='scope.row.user.displayName' - :style='{ color: scope.row.user.$userColour }') - span(v-else v-text='scope.row.user.displayName') - el-table-column( - :label='$t("dialog.group_member_moderation.notes")' - prop='managerNotes' - sortable) - template(#default='scope') - span(v-text='scope.row.managerNotes' @click.stop) - br - el-button( - @click='groupMembersDeleteSentInvite' - :disabled='groupMemberModeration.progressCurrent || !hasGroupPermission(groupDialog.ref, "group-invites-manage")') {{ $t('dialog.group_member_moderation.delete_sent_invite') }} - el-tab-pane - span(slot='label') - span( - v-text='$t("dialog.group_member_moderation.join_requests")' - style='font-weight: bold; font-size: 16px') - span(style='color: #909399; font-size: 12px; margin-left: 5px') {{ groupJoinRequestsModerationTable.data.length }} - el-button(size='small' @click='selectAllGroupJoinRequests') {{ $t('dialog.group_member_moderation.select_all') }} - data-tables(v-bind='groupJoinRequestsModerationTable' style='margin-top: 10px') - el-table-column( - width='55' - prop='$selected' - :key='groupMemberModerationTableForceUpdate') - template(#default='scope') - el-button(type='text' size='mini' @click.stop) - el-checkbox( - v-model='scope.row.$selected' - @change='groupMemberModerationTableSelectionChange(scope.row)') - el-table-column( - :label='$t("dialog.group_member_moderation.avatar")' - width='70' - prop='photo') - template(#default='scope') - el-popover(placement='right' height='500px' trigger='hover') - img.friends-list-avatar( - slot='reference' - v-lazy='userImage(scope.row.user)') - img.friends-list-avatar( - v-lazy='userImageFull(scope.row.user)' - style='height: 500px; cursor: pointer' - @click='showFullscreenImageDialog(userImageFull(scope.row.user))') - el-table-column( - :label='$t("dialog.group_member_moderation.display_name")' - width='160' - prop='$displayName' - sortable) - template(#default='scope') - span(style='cursor: pointer' @click='showUserDialog(scope.row.userId)') - span( - v-if='randomUserColours' - v-text='scope.row.user.displayName' - :style='{ color: scope.row.user.$userColour }') - span(v-else v-text='scope.row.user.displayName') - el-table-column( - :label='$t("dialog.group_member_moderation.notes")' - prop='managerNotes' - sortable) - template(#default='scope') - span(v-text='scope.row.managerNotes' @click.stop) - br - el-button( - @click='groupMembersAcceptInviteRequest' - :disabled='groupMemberModeration.progressCurrent || !hasGroupPermission(groupDialog.ref, "group-invites-manage")') {{ $t('dialog.group_member_moderation.accept_join_requests') }} - el-button( - @click='groupMembersRejectInviteRequest' - :disabled='groupMemberModeration.progressCurrent || !hasGroupPermission(groupDialog.ref, "group-invites-manage")') {{ $t('dialog.group_member_moderation.reject_join_requests') }} - el-button( - @click='groupMembersBlockJoinRequest' - :disabled='groupMemberModeration.progressCurrent || !hasGroupPermission(groupDialog.ref, "group-invites-manage")') {{ $t('dialog.group_member_moderation.block_join_requests') }} - el-tab-pane - span(slot='label') - span( - v-text='$t("dialog.group_member_moderation.blocked_requests")' - style='font-weight: bold; font-size: 16px') - span(style='color: #909399; font-size: 12px; margin-left: 5px') {{ groupBlockedModerationTable.data.length }} - el-button(size='small' @click='selectAllGroupBlocked') {{ $t('dialog.group_member_moderation.select_all') }} - data-tables(v-bind='groupBlockedModerationTable' style='margin-top: 10px') - el-table-column( - width='55' - prop='$selected' - :key='groupMemberModerationTableForceUpdate') - template(#default='scope') - el-button(type='text' size='mini' @click.stop) - el-checkbox( - v-model='scope.row.$selected' - @change='groupMemberModerationTableSelectionChange(scope.row)') - el-table-column( - :label='$t("dialog.group_member_moderation.avatar")' - width='70' - prop='photo') - template(#default='scope') - el-popover(placement='right' height='500px' trigger='hover') - img.friends-list-avatar( - slot='reference' - v-lazy='userImage(scope.row.user)') - img.friends-list-avatar( - v-lazy='userImageFull(scope.row.user)' - style='height: 500px; cursor: pointer' - @click='showFullscreenImageDialog(userImageFull(scope.row.user))') - el-table-column( - :label='$t("dialog.group_member_moderation.display_name")' - width='160' - prop='$displayName' - sortable) - template(#default='scope') - span(style='cursor: pointer' @click='showUserDialog(scope.row.userId)') - span( - v-if='randomUserColours' - v-text='scope.row.user.displayName' - :style='{ color: scope.row.user.$userColour }') - span(v-else v-text='scope.row.user.displayName') - el-table-column( - :label='$t("dialog.group_member_moderation.notes")' - prop='managerNotes' - sortable) - template(#default='scope') - span(v-text='scope.row.managerNotes' @click.stop) - br - el-button( - @click='groupMembersDeleteBlockedRequest' - :disabled='groupMemberModeration.progressCurrent || !hasGroupPermission(groupDialog.ref, "group-invites-manage")') {{ $t('dialog.group_member_moderation.delete_blocked_requests') }} - el-tab-pane( - :label='$t("dialog.group_member_moderation.logs")' - :disabled='!hasGroupPermission(groupDialog.ref, "group-audit-view")') - div(style='margin-top: 10px') - el-button( - type='default' - @click='getAllGroupLogs(groupMemberModeration.id)' - size='mini' - icon='el-icon-refresh' - :loading='isGroupMembersLoading' - circle) - span(style='font-size: 14px; margin-left: 5px; margin-right: 5px') {{ groupLogsModerationTable.data.length }} - br - div(style='display: flex; justify-content: space-between; align-items: center') - div - el-select( - v-model='groupMemberModeration.selectedAuditLogTypes' - multiple - collapse-tags - :placeholder='$t("dialog.group_member_moderation.filter_type")') - el-option-group(:label='$t("dialog.group_member_moderation.select_type")') - el-option.x-friend-item( - v-for='type in groupMemberModeration.auditLogTypes' - :key='type' - :label='getAuditLogTypeName(type)' - :value='type') - .detail - span.name(v-text='getAuditLogTypeName(type)') - el-input( - v-model='groupLogsModerationTable.filters[0].value' - :placeholder='$t("dialog.group_member_moderation.search_placeholder")' - style='display: inline-block; width: 150px; margin: 10px') - div - el-button(@click='showGroupLogsExportDialog') {{ $t('dialog.group_member_moderation.export_logs') }} - br - data-tables(v-bind='groupLogsModerationTable' style='margin-top: 10px') - el-table-column( - :label='$t("dialog.group_member_moderation.created_at")' - width='170' - prop='created_at' - sortable) - template(#default='scope') - span {{ scope.row.created_at | formatDate('long') }} - el-table-column( - :label='$t("dialog.group_member_moderation.type")' - width='190' - prop='eventType' - sortable) - template(#default='scope') - span(v-text='scope.row.eventType') - el-table-column( - :label='$t("dialog.group_member_moderation.display_name")' - width='160' - prop='actorDisplayName' - sortable) - template(#default='scope') - span(style='cursor: pointer' @click='showUserDialog(scope.row.actorId)') - span(v-text='scope.row.actorDisplayName') - el-table-column(:label='$t("dialog.group_member_moderation.description")' prop='description') - template(#default='scope') - span(v-text='scope.row.description') - el-table-column(:label='$t("dialog.group_member_moderation.data")' prop='data') - template(#default='scope') - span(v-if='Object.keys(scope.row.data).length' v-text='JSON.stringify(scope.row.data)') - br - br - span.name {{ $t('dialog.group_member_moderation.user_id') }} - br - el-input( - v-model='groupMemberModeration.selectUserId' - size='mini' - style='margin-top: 5px; width: 340px' - :placeholder='$t("dialog.group_member_moderation.user_id_placeholder")' - clearable) - el-button(size='small' @click='selectGroupMemberUserId' :disabled='!groupMemberModeration.selectUserId') {{ $t('dialog.group_member_moderation.select_user') }} - br - br - span.name {{ $t('dialog.group_member_moderation.selected_users') }} - el-button( - type='default' - @click='clearSelectedGroupMembers' - size='mini' - icon='el-icon-delete' - circle - style='margin-left: 5px') - br - el-tag( - v-for='user in groupMemberModeration.selectedUsersArray' - type='info' - disable-transitions='true' - :key='user.id' - style='margin-right: 5px; margin-top: 5px' - closable - @close='deleteSelectedGroupMember(user)') - span {{ user.user?.displayName }} #[i.el-icon-warning(v-if='user.membershipStatus !== "member"' style='margin-left: 5px')] - br - br - span.name {{ $t('dialog.group_member_moderation.notes') }} - el-input.extra( - v-model='groupMemberModeration.note' - type='textarea' - :rows='2' - :autosize='{ minRows: 1, maxRows: 20 }' - :placeholder='$t("dialog.group_member_moderation.note_placeholder")' - size='mini' - resize='none' - style='margin-top: 5px') - br - br - span.name {{ $t('dialog.group_member_moderation.selected_roles') }} - br - el-select( - v-model='groupMemberModeration.selectedRoles' - clearable - multiple - :placeholder='$t("dialog.group_member_moderation.choose_roles_placeholder")' - filterable - style='margin-top: 5px') - el-option-group(:label='$t("dialog.group_member_moderation.roles")') - el-option.x-friend-item( - v-for='role in groupMemberModeration.groupRef.roles' - :key='role.id' - :label='role.name' - :value='role.id' - style='height: auto') - .detail - span.name(v-text='role.name') - br - br - span.name {{ $t('dialog.group_member_moderation.actions') }} - br - el-button( - @click='groupMembersAddRoles' - :disabled='!groupMemberModeration.selectedRoles.length || groupMemberModeration.progressCurrent || !hasGroupPermission(groupDialog.ref, "group-roles-assign")') {{ $t('dialog.group_member_moderation.add_roles') }} - el-button( - @click='groupMembersRemoveRoles' - :disabled='!groupMemberModeration.selectedRoles.length || groupMemberModeration.progressCurrent || !hasGroupPermission(groupDialog.ref, "group-roles-assign")') {{ $t('dialog.group_member_moderation.remove_roles') }} - el-button( - @click='groupMembersSaveNote' - :disabled='groupMemberModeration.progressCurrent || !hasGroupPermission(groupDialog.ref, "group-members-manage")') {{ $t('dialog.group_member_moderation.save_note') }} - el-button( - @click='groupMembersKick' - :disabled='groupMemberModeration.progressCurrent || !hasGroupPermission(groupDialog.ref, "group-members-remove")') {{ $t('dialog.group_member_moderation.kick') }} - el-button( - @click='groupMembersBan' - :disabled='groupMemberModeration.progressCurrent || !hasGroupPermission(groupDialog.ref, "group-bans-manage")') {{ $t('dialog.group_member_moderation.ban') }} - el-button( - @click='groupMembersUnban' - :disabled='groupMemberModeration.progressCurrent || !hasGroupPermission(groupDialog.ref, "group-bans-manage")') {{ $t('dialog.group_member_moderation.unban') }} - span(v-if='groupMemberModeration.progressCurrent' style='margin-top: 10px') #[i.el-icon-loading(style='margin-left: 5px; margin-right: 5px')] {{ $t('dialog.group_member_moderation.progress') }} {{ groupMemberModeration.progressCurrent }}/{{ groupMemberModeration.progressTotal }} - el-button( - v-if='groupMemberModeration.progressCurrent' - @click='groupMemberModeration.progressTotal = 0' - style='margin-left: 5px') {{ $t('dialog.group_member_moderation.cancel') }} - - //- dialog: group posts - el-dialog.x-dialog( - :before-close='beforeDialogClose' - @mousedown.native='dialogMouseDown' - @mouseup.native='dialogMouseUp' - ref='groupPostEditDialog' - :visible.sync='groupPostEditDialog.visible' - :title='$t("dialog.group_post_edit.header")' - width='650px') - div(v-if='groupPostEditDialog.visible') - h3(v-text='groupPostEditDialog.groupRef.name') - el-form(:model='groupPostEditDialog' label-width='150px') - el-form-item(:label='$t("dialog.group_post_edit.title")') - el-input(v-model='groupPostEditDialog.title' size='mini') - el-form-item(:label='$t("dialog.group_post_edit.message")') - el-input( - v-model='groupPostEditDialog.text' - type='textarea' - :rows='4' - :autosize='{ minRows: 4, maxRows: 20 }' - style='margin-top: 10px' - resize='none') - el-form-item - el-checkbox( - v-if='!groupPostEditDialog.postId' - v-model='groupPostEditDialog.sendNotification' - size='small') {{ $t('dialog.group_post_edit.send_notification') }} - el-form-item(:label='$t("dialog.group_post_edit.post_visibility")') - el-radio-group(v-model='groupPostEditDialog.visibility' size='small') - el-radio(label='public') {{ $t('dialog.group_post_edit.visibility_public') }} - el-radio(label='group') {{ $t('dialog.group_post_edit.visibility_group') }} - el-form-item( - v-if='groupPostEditDialog.visibility === "group"' - :label='$t("dialog.new_instance.roles")') - el-select( - v-model='groupPostEditDialog.roleIds' - multiple - clearable - :placeholder='$t("dialog.new_instance.role_placeholder")' - style='width: 100%') - el-option-group(:label='$t("dialog.new_instance.role_placeholder")') - el-option.x-friend-item( - v-for='role in groupPostEditDialog.groupRef?.roles' - :key='role.id' - :label='role.name' - :value='role.id' - style='height: auto; width: 478px') - .detail - span.name(v-text='role.name') - el-form-item(:label='$t("dialog.group_post_edit.image")') - 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') }} - - template(#footer) - el-button(size='small' @click='groupPostEditDialog.visible = false') {{ $t('dialog.group_post_edit.cancel') }} - el-button(v-if='groupPostEditDialog.postId' size='small' @click='editGroupPost') {{ $t('dialog.group_post_edit.edit_post') }} - el-button(v-else size='small' @click='createGroupPost') {{ $t('dialog.group_post_edit.create_post') }} - - //- dialog: export logs - el-dialog.x-dialog( - :before-close='beforeDialogClose' - @mousedown.native='dialogMouseDown' - @mouseup.native='dialogMouseUp' - :visible.sync='isGroupLogsExportDialogVisible' - :title='$t("dialog.group_member_moderation.export_logs")' - width='650px' - ref='groupLogsExportDialogRef') - el-checkbox-group( - v-model='checkedGroupLogsExportLogsOptions' - @change='updateGrouptLogsExporContent()' - style='margin-bottom: 10px') - template(v-for='option in checkGroupsLogsExportLogsOptions') - el-checkbox(:key='option.label' :label='option.label') {{ $t(option.text) }} - br - el-input( - type='textarea' - v-model='groupLogsExportContent' - size='mini' - rows='15' - resize='none' - readonly - style='margin-top: 15px' - @click.native='handleCopyGroupLogsExportContent') diff --git a/src/mixins/tabs/notifications.pug b/src/mixins/tabs/notifications.pug index f36ece8e..0eff233d 100644 --- a/src/mixins/tabs/notifications.pug +++ b/src/mixins/tabs/notifications.pug @@ -106,9 +106,13 @@ mixin notificationsTab :grouphint='scope.row.details.groupName' :link='true') br - span( + el-tooltip( v-if='scope.row.message && scope.row.message !== `This is a generated invite to ${scope.row.details?.worldName}`' - v-text='scope.row.message') + placement='top') + template(#content) + pre.extra( + style='display: inline-block; vertical-align: top; font-family: inherit; font-size: 12px; white-space: pre-wrap; margin: 0') {{ scope.row.message || '-' }} + div(v-text='scope.row.message') span( v-else-if='scope.row.details && scope.row.details.inviteMessage' v-text='scope.row.details.inviteMessage') diff --git a/src/views/dialogs/groupDialog/GroupDialog.vue b/src/views/dialogs/groupDialog/GroupDialog.vue new file mode 100644 index 00000000..88182f7a --- /dev/null +++ b/src/views/dialogs/groupDialog/GroupDialog.vue @@ -0,0 +1,1789 @@ + + + diff --git a/src/views/dialogs/groupDialog/GroupMemberModerationDialog.vue b/src/views/dialogs/groupDialog/GroupMemberModerationDialog.vue new file mode 100644 index 00000000..1c10bb40 --- /dev/null +++ b/src/views/dialogs/groupDialog/GroupMemberModerationDialog.vue @@ -0,0 +1,1690 @@ + + + diff --git a/src/views/dialogs/groupDialog/GroupMemberModerationExportDialog.vue b/src/views/dialogs/groupDialog/GroupMemberModerationExportDialog.vue new file mode 100644 index 00000000..3ae8f907 --- /dev/null +++ b/src/views/dialogs/groupDialog/GroupMemberModerationExportDialog.vue @@ -0,0 +1,110 @@ + + + diff --git a/src/views/dialogs/groupDialog/GroupPostEditDialog.vue b/src/views/dialogs/groupDialog/GroupPostEditDialog.vue new file mode 100644 index 00000000..0d140f5f --- /dev/null +++ b/src/views/dialogs/groupDialog/GroupPostEditDialog.vue @@ -0,0 +1,200 @@ + + + diff --git a/src/views/dialogs/groupDialog/InviteGroupDialog.vue b/src/views/dialogs/groupDialog/InviteGroupDialog.vue new file mode 100644 index 00000000..cf2017ad --- /dev/null +++ b/src/views/dialogs/groupDialog/InviteGroupDialog.vue @@ -0,0 +1,307 @@ + + + diff --git a/src/views/dialogs/world/NewInstanceDialog.vue b/src/views/dialogs/world/NewInstanceDialog.vue index 09138929..0077d30a 100644 --- a/src/views/dialogs/world/NewInstanceDialog.vue +++ b/src/views/dialogs/world/NewInstanceDialog.vue @@ -490,7 +490,7 @@