From 1cad66bb2cf487c88b7da3a74d47519fba4ed314 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 27 Sep 2024 13:28:27 -0400 Subject: [PATCH] perf(admin): speed up admin tabs significantly (#16363) Iterates #16043 * fix(admin): improve admin panel loading by putting sections in loaders * fix(admin): speed up members tab by using nim model and real search * fix(admin): speed up airdrop panel * fix(admin): mint panel and airdrop panel interactions and previous btn * fix(admin): speed up overview page * fix(admin): speed up permissions page --- .../modules/main/communities/io_interface.nim | 3 + src/app/modules/main/communities/module.nim | 19 + src/app/modules/main/communities/view.nim | 3 + ui/app/AppLayouts/Chat/stores/RootStore.qml | 4 + .../models/ChannelPermissionsModelEditor.qml | 2 +- .../panels/AirdropsSettingsPanel.qml | 1 + .../Communities/panels/MembersTabPanel.qml | 33 +- .../panels/OverviewSettingsPanel.qml | 8 + .../panels/PermissionsSettingsPanel.qml | 67 +-- .../Communities/views/CommunityColumnView.qml | 2 +- .../views/CommunitySettingsView.qml | 563 +++++++++--------- .../Communities/views/PermissionsView.qml | 19 +- .../Profile/panels/ContactsListPanel.qml | 7 - ui/imports/shared/stores/PermissionsStore.qml | 14 - 14 files changed, 397 insertions(+), 348 deletions(-) diff --git a/src/app/modules/main/communities/io_interface.nim b/src/app/modules/main/communities/io_interface.nim index 151d144559..1f78cfc8b1 100644 --- a/src/app/modules/main/communities/io_interface.nim +++ b/src/app/modules/main/communities/io_interface.nim @@ -236,6 +236,9 @@ method joinCommunityOrEditSharedAddresses*(self: AccessInterface) {.base.} = method prepareTokenModelForCommunity*(self: AccessInterface, communityId: string) {.base.} = raise newException(ValueError, "No implementation available") +method prepareTokenModelForCommunityChat*(self: AccessInterface, communityId: string, chatId: string) {.base.} = + raise newException(ValueError, "No implementation available") + method getCommunityPublicKeyFromPrivateKey*(self: AccessInterface, communityPrivateKey: string): string {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/communities/module.nim b/src/app/modules/main/communities/module.nim index 0a5bf04d12..dad638c7e7 100644 --- a/src/app/modules/main/communities/module.nim +++ b/src/app/modules/main/communities/module.nim @@ -886,6 +886,25 @@ method prepareTokenModelForCommunity*(self: Module, communityId: string) = self.view.spectatedCommunityPermissionModel.setItems(tokenPermissionsItems) self.checkPermissions(communityId, @[]) +method prepareTokenModelForCommunityChat*(self: Module, communityId: string, chatId: string) = + let community = self.controller.getCommunityById(communityId) + var tokenPermissionsItems: seq[TokenPermissionItem] = @[] + for id, tokenPermission in community.tokenPermissions: + var containsChat = false + for id in tokenPermission.chatIds: + if id == chatId: + containsChat = true + break + if not containsChat: + continue + + let chats = community.getCommunityChats(tokenPermission.chatIds) + let tokenPermissionItem = buildTokenPermissionItem(tokenPermission, chats) + tokenPermissionsItems.add(tokenPermissionItem) + + self.view.spectatedCommunityPermissionModel.setItems(tokenPermissionsItems) + self.checkPermissions(communityId, @[]) + proc applyPermissionResponse*(self: Module, communityId: string, permissions: Table[string, CheckPermissionsResultDto]) = let community = self.controller.getCommunityById(communityId) for id, criteriaResult in permissions: diff --git a/src/app/modules/main/communities/view.nim b/src/app/modules/main/communities/view.nim index 1837a88e1c..8e39516844 100644 --- a/src/app/modules/main/communities/view.nim +++ b/src/app/modules/main/communities/view.nim @@ -347,6 +347,9 @@ QtObject: proc prepareTokenModelForCommunity(self: View, communityId: string) {.slot.} = self.delegate.prepareTokenModelForCommunity(communityId) + proc prepareTokenModelForCommunityChat(self: View, communityId: string, chatId: string) {.slot.} = + self.delegate.prepareTokenModelForCommunityChat(communityId, chatId) + proc signProfileKeypairAndAllNonKeycardKeypairs*(self: View) {.slot.} = self.delegate.signProfileKeypairAndAllNonKeycardKeypairs() diff --git a/ui/app/AppLayouts/Chat/stores/RootStore.qml b/ui/app/AppLayouts/Chat/stores/RootStore.qml index ad08df848f..8af03fb94a 100644 --- a/ui/app/AppLayouts/Chat/stores/RootStore.qml +++ b/ui/app/AppLayouts/Chat/stores/RootStore.qml @@ -132,6 +132,10 @@ QtObject { root.communitiesModuleInst.prepareTokenModelForCommunity(publicKey) } + function prepareTokenModelForCommunityChat(publicKey, chatId) { + root.communitiesModuleInst.prepareTokenModelForCommunityChat(publicKey, chatId) + } + readonly property bool allChannelsAreHiddenBecauseNotPermitted: root.chatCommunitySectionModule.allChannelsAreHiddenBecauseNotPermitted && !root.chatCommunitySectionModule.requiresTokenPermissionToJoin diff --git a/ui/app/AppLayouts/Communities/models/ChannelPermissionsModelEditor.qml b/ui/app/AppLayouts/Communities/models/ChannelPermissionsModelEditor.qml index c9fb508b36..709bf6d65a 100644 --- a/ui/app/AppLayouts/Communities/models/ChannelPermissionsModelEditor.qml +++ b/ui/app/AppLayouts/Communities/models/ChannelPermissionsModelEditor.qml @@ -252,7 +252,7 @@ QtObject { filters: [ FastExpressionFilter { function filterPredicate(id, permissionType) { - return !PermissionTypes.isCommunityPermission(permissionType) && root.permissionsModel.belongsToChat(id, root.channelId) + return !PermissionTypes.isCommunityPermission(permissionType) } expression: { return filterPredicate(model.id, model.permissionType) diff --git a/ui/app/AppLayouts/Communities/panels/AirdropsSettingsPanel.qml b/ui/app/AppLayouts/Communities/panels/AirdropsSettingsPanel.qml index 2529569972..ef7da183c1 100644 --- a/ui/app/AppLayouts/Communities/panels/AirdropsSettingsPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/AirdropsSettingsPanel.qml @@ -3,6 +3,7 @@ import QtQuick.Controls 2.15 import StatusQ.Controls 0.1 +import AppLayouts.Communities.controls 1.0 import AppLayouts.Communities.layouts 1.0 import AppLayouts.Communities.views 1.0 import AppLayouts.Communities.helpers 1.0 diff --git a/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml b/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml index 399a966c37..8d23316b1a 100644 --- a/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml @@ -5,6 +5,7 @@ import QtQuick.Controls 2.14 import StatusQ 0.1 import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 +import StatusQ.Core.Utils 0.1 import StatusQ.Controls 0.1 import StatusQ.Components 0.1 import StatusQ.Popups 0.1 @@ -70,23 +71,31 @@ Item { sourceModel: root.model - proxyRoles: FastExpressionRole { - function displayNameProxy(localNickname, ensName, displayName, aliasName) { - return ProfileUtils.displayName(localNickname, ensName, displayName, aliasName); - } - - name: "preferredDisplayName" - expectedRoles: ["localNickname", "displayName", "ensName", "alias"] - expression: displayNameProxy(model.localNickname, model.ensName, model.displayName, model.alias); - } - - sorters : [ StringSorter { roleName: "preferredDisplayName" caseSensitivity: Qt.CaseInsensitive } ] + + filters: AnyOf { + SearchFilter { + roleName: "localNickname" + searchPhrase: memberSearch.text + } + SearchFilter { + roleName: "displayName" + searchPhrase: memberSearch.text + } + SearchFilter { + roleName: "ensName" + searchPhrase: memberSearch.text + } + SearchFilter { + roleName: "alias" + searchPhrase: memberSearch.text + } + } } spacing: 0 @@ -288,8 +297,6 @@ Item { readonly property string title: model.preferredDisplayName width: membersList.width - visible: memberSearch.text === "" || title.toLowerCase().includes(memberSearch.text.toLowerCase()) - height: visible ? implicitHeight : 0 color: "transparent" pubKey: model.isEnsVerified ? "" : Utils.getElidedCompressedPk(model.pubKey) diff --git a/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml b/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml index b45116ee9b..176262749e 100644 --- a/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml @@ -258,6 +258,14 @@ StackLayout { contentItem: Loader { id: editSettingsPanelLoader + active: false + + onVisibleChanged: { + if (visible) { + active = true + } + } + function reloadContent() { active = false active = true diff --git a/ui/app/AppLayouts/Communities/panels/PermissionsSettingsPanel.qml b/ui/app/AppLayouts/Communities/panels/PermissionsSettingsPanel.qml index a2dc27ea5f..b43af66851 100644 --- a/ui/app/AppLayouts/Communities/panels/PermissionsSettingsPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/PermissionsSettingsPanel.qml @@ -99,52 +99,47 @@ StackView { onClicked: root.push(newPermissionView, StackView.Immediate) } - contentItem: StatusScrollView { - contentHeight: (permissionsView.height + topPadding) - topPadding: permissionsView.topPadding - padding: 0 - PermissionsView { - id: permissionsView - permissionsModel: root.permissionsModel - assetsModel: root.assetsModel - collectiblesModel: root.collectiblesModel - channelsModel: allChannelsTransformed + contentItem: PermissionsView { + id: permissionsView + permissionsModel: root.permissionsModel + assetsModel: root.assetsModel + collectiblesModel: root.collectiblesModel + channelsModel: allChannelsTransformed - communityDetails: root.communityDetails + communityDetails: root.communityDetails - viewWidth: root.viewWidth + viewWidth: root.viewWidth - onEditPermissionRequested: { - const item = ModelUtils.get(root.permissionsModel, index) + onEditPermissionRequested: { + const item = ModelUtils.get(root.permissionsModel, index) - const properties = { - permissionKeyToEdit: item.key, - holdingsToEditModel: item.holdingsListModel, - channelsToEditModel: item.channelsListModel, - permissionTypeToEdit: item.permissionType, - isPrivateToEditValue: item.isPrivate - } - - root.pushEditView(properties); + const properties = { + permissionKeyToEdit: item.key, + holdingsToEditModel: item.holdingsListModel, + channelsToEditModel: item.channelsListModel, + permissionTypeToEdit: item.permissionType, + isPrivateToEditValue: item.isPrivate } - onDuplicatePermissionRequested: { - const item = ModelUtils.get(root.permissionsModel, index) + root.pushEditView(properties); + } - const properties = { - holdingsToEditModel: item.holdingsListModel, - channelsToEditModel: item.channelsListModel, - permissionTypeToEdit: item.permissionType, - isPrivateToEditValue: item.isPrivate - } + onDuplicatePermissionRequested: { + const item = ModelUtils.get(root.permissionsModel, index) - root.pushEditView(properties); + const properties = { + holdingsToEditModel: item.holdingsListModel, + channelsToEditModel: item.channelsListModel, + permissionTypeToEdit: item.permissionType, + isPrivateToEditValue: item.isPrivate } - onRemovePermissionRequested: { - const key = ModelUtils.get(root.permissionsModel, index, "key") - root.removePermissionRequested(key) - } + root.pushEditView(properties); + } + + onRemovePermissionRequested: { + const key = ModelUtils.get(root.permissionsModel, index, "key") + root.removePermissionRequested(key) } } } diff --git a/ui/app/AppLayouts/Communities/views/CommunityColumnView.qml b/ui/app/AppLayouts/Communities/views/CommunityColumnView.qml index 9d328a6d22..0f01accc21 100644 --- a/ui/app/AppLayouts/Communities/views/CommunityColumnView.qml +++ b/ui/app/AppLayouts/Communities/views/CommunityColumnView.qml @@ -545,7 +545,7 @@ Item { collectiblesModel: root.store.collectiblesModel ensCommunityPermissionsEnabled: root.store.ensCommunityPermissionsEnabled permissionsModel: { - root.store.prepareTokenModelForCommunity(communityData.id) + root.store.prepareTokenModelForCommunityChat(communityData.id, chatId) return root.store.permissionsModel } channelsModel: root.store.chatCommunitySectionModule.model diff --git a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml index 45d3b27f66..ccac100a10 100644 --- a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml +++ b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml @@ -4,6 +4,7 @@ import QtQuick.Dialogs 1.3 import SortFilterProxyModel 0.2 +import StatusQ 0.1 import StatusQ.Components 0.1 import StatusQ.Controls 0.1 import StatusQ.Core 0.1 @@ -74,14 +75,19 @@ StatusSectionLayout { signal backToCommunityClicked - backButtonName: stackLayout.children[d.currentIndex].previousPageName || "" + backButtonName: { + if (!stackLayout.children[d.currentIndex].item || !stackLayout.children[d.currentIndex].item.previousPageName) { + return "" + } + return stackLayout.children[d.currentIndex].item.previousPageName + } //navigate to a specific section and subsection function goTo(section: int, subSection: int) { d.goTo(section, subSection) } - onBackButtonClicked: stackLayout.children[d.currentIndex].navigateBack() + onBackButtonClicked: stackLayout.children[d.currentIndex].item.navigateBack() leftPanel: Item { anchors.fill: parent @@ -167,387 +173,407 @@ StatusSectionLayout { currentIndex: d.currentIndex - OverviewSettingsPanel { + onCurrentIndexChanged: { + children[currentIndex].active = true + } + + // OVERVIEW + Loader { + active: true + readonly property int sectionKey: Constants.CommunitySettingsSections.Overview readonly property string sectionName: qsTr("Overview") readonly property string sectionIcon: "show" readonly property bool sectionEnabled: true - isOwner: root.isOwner - isAdmin: root.isAdmin - isTokenMaster: root.isTokenMasterOwner - communityId: root.community.id - name: root.community.name - description: root.community.description - introMessage: root.community.introMessage - outroMessage: root.community.outroMessage - logoImageData: root.community.image - bannerImageData: root.community.bannerImageData - color: root.community.color - tags: root.rootStore.communityTags - selectedTags: root.filteredSelectedTags - archiveSupportEnabled: root.community.historyArchiveSupportEnabled - archiveSupporVisible: root.community.isControlNode - requestToJoinEnabled: root.community.access === Constants.communityChatOnRequestAccess - pinMessagesEnabled: root.community.pinMessageAllMembersEnabled - editable: true - loginType: root.rootStore.loginType - isControlNode: root.isControlNode - communitySettingsDisabled: root.communitySettingsDisabled - overviewChartData: rootStore.overviewChartData - shardingEnabled: !isAdmin && !isTokenMaster && localAppSettings.wakuV2ShardedCommunitiesEnabled - shardIndex: root.community.shardIndex - shardingInProgress: root.chatCommunitySectionModule.shardingInProgress - pubsubTopic: root.community.pubsubTopic - pubsubTopicKey: root.community.pubsubTopicKey + sourceComponent: OverviewSettingsPanel { + isOwner: root.isOwner + isAdmin: root.isAdmin + isTokenMaster: root.isTokenMasterOwner + communityId: root.community.id + name: root.community.name + description: root.community.description + introMessage: root.community.introMessage + outroMessage: root.community.outroMessage + logoImageData: root.community.image + bannerImageData: root.community.bannerImageData + color: root.community.color + tags: root.rootStore.communityTags + selectedTags: root.filteredSelectedTags + archiveSupportEnabled: root.community.historyArchiveSupportEnabled + archiveSupporVisible: root.community.isControlNode + requestToJoinEnabled: root.community.access === Constants.communityChatOnRequestAccess + pinMessagesEnabled: root.community.pinMessageAllMembersEnabled + editable: true + loginType: root.rootStore.loginType + isControlNode: root.isControlNode + communitySettingsDisabled: root.communitySettingsDisabled + overviewChartData: rootStore.overviewChartData + shardingEnabled: !isAdmin && !isTokenMaster && localAppSettings.wakuV2ShardedCommunitiesEnabled + shardIndex: root.community.shardIndex + shardingInProgress: root.chatCommunitySectionModule.shardingInProgress + pubsubTopic: root.community.pubsubTopic + pubsubTopicKey: root.community.pubsubTopicKey - sendModalPopup: root.sendModalPopup - ownerToken: tokensModelChangesTracker.ownerToken + sendModalPopup: root.sendModalPopup + ownerToken: tokensModelChangesTracker.ownerToken - isPendingOwnershipRequest: root.isPendingOwnershipRequest + isPendingOwnershipRequest: root.isPendingOwnershipRequest - onFinaliseOwnershipClicked: root.finaliseOwnershipClicked() + onFinaliseOwnershipClicked: root.finaliseOwnershipClicked() - onCollectCommunityMetricsMessagesCount: { - rootStore.collectCommunityMetricsMessagesCount(intervals) - } - - onEdited: { - const error = root.chatCommunitySectionModule.editCommunity( - StatusQUtils.Utils.filterXSS(item.name), - StatusQUtils.Utils.filterXSS(item.description), - StatusQUtils.Utils.filterXSS(item.introMessage), - StatusQUtils.Utils.filterXSS(item.outroMessage), - item.options.requestToJoinEnabled ? Constants.communityChatOnRequestAccess - : Constants.communityChatPublicAccess, - item.color.toString().toUpperCase(), - item.selectedTags, - Utils.getImageAndCropInfoJson(item.logoImagePath, item.logoCropRect), - Utils.getImageAndCropInfoJson(item.bannerPath, item.bannerCropRect), - item.options.archiveSupportEnabled, - item.options.pinMessagesEnabled - ) - if (error) { - errorDialog.text = error.error - errorDialog.open() + onCollectCommunityMetricsMessagesCount: { + rootStore.collectCommunityMetricsMessagesCount(intervals) } - } - onInviteNewPeopleClicked: { - Global.openInviteFriendsToCommunityPopup(root.community, - root.chatCommunitySectionModule, - null) - } + onEdited: { + const error = root.chatCommunitySectionModule.editCommunity( + StatusQUtils.Utils.filterXSS(item.name), + StatusQUtils.Utils.filterXSS(item.description), + StatusQUtils.Utils.filterXSS(item.introMessage), + StatusQUtils.Utils.filterXSS(item.outroMessage), + item.options.requestToJoinEnabled ? Constants.communityChatOnRequestAccess + : Constants.communityChatPublicAccess, + item.color.toString().toUpperCase(), + item.selectedTags, + Utils.getImageAndCropInfoJson(item.logoImagePath, item.logoCropRect), + Utils.getImageAndCropInfoJson(item.bannerPath, item.bannerCropRect), + item.options.archiveSupportEnabled, + item.options.pinMessagesEnabled + ) + if (error) { + errorDialog.text = error.error + errorDialog.open() + } + } - onAirdropTokensClicked: root.goTo(Constants.CommunitySettingsSections.Airdrops) - onExportControlNodeClicked: { - if(!root.isControlNode) - return + onInviteNewPeopleClicked: { + Global.openInviteFriendsToCommunityPopup(root.community, + root.chatCommunitySectionModule, + null) + } - Global.openExportControlNodePopup(root.community) - } + onAirdropTokensClicked: root.goTo(Constants.CommunitySettingsSections.Airdrops) + onExportControlNodeClicked: { + if(!root.isControlNode) + return - onImportControlNodeClicked: { - if(root.isControlNode) - return + Global.openExportControlNodePopup(root.community) + } - Global.openImportControlNodePopup(root.community) - } + onImportControlNodeClicked: { + if(root.isControlNode) + return - onMintOwnerTokenClicked: { - root.goTo(Constants.CommunitySettingsSections.MintTokens) - mintPanel.openNewTokenForm(false/*Collectible owner token*/) - } + Global.openImportControlNodePopup(root.community) + } - onShardIndexEdited: if (root.community.shardIndex !== shardIndex) { - root.chatCommunitySectionModule.setCommunityShard(shardIndex) + onMintOwnerTokenClicked: { + root.goTo(Constants.CommunitySettingsSections.MintTokens) + mintPanel.openNewTokenForm(false/*Collectible owner token*/) + } + + onShardIndexEdited: if (root.community.shardIndex !== shardIndex) { + root.chatCommunitySectionModule.setCommunityShard(shardIndex) + } } } - MembersSettingsPanel { + // MEMBERS + Loader { + active: false + readonly property int sectionKey: Constants.CommunitySettingsSections.Members readonly property string sectionName: qsTr("Members") readonly property string sectionIcon: "group-chat" readonly property bool sectionEnabled: true - rootStore: root.rootStore - membersModel: root.community.members - bannedMembersModel: root.community.bannedMembers - pendingMemberRequestsModel: root.community.pendingMemberRequests - declinedMemberRequestsModel: root.community.declinedMemberRequests - editable: root.isAdmin || root.isOwner || root.isTokenMasterOwner - memberRole: community.memberRole - communityName: root.community.name + sourceComponent: MembersSettingsPanel { + rootStore: root.rootStore + membersModel: root.community.members + bannedMembersModel: root.community.bannedMembers + pendingMemberRequestsModel: root.community.pendingMemberRequests + declinedMemberRequestsModel: root.community.declinedMemberRequests + editable: root.isAdmin || root.isOwner || root.isTokenMasterOwner + memberRole: community.memberRole + communityName: root.community.name - onKickUserClicked: root.rootStore.removeUserFromCommunity(id) - onBanUserClicked: root.rootStore.banUserFromCommunity(id, deleteAllMessages) - onUnbanUserClicked: root.rootStore.unbanUserFromCommunity(id) - onAcceptRequestToJoin: root.rootStore.acceptRequestToJoinCommunity(id, root.community.id) - onDeclineRequestToJoin: root.rootStore.declineRequestToJoinCommunity(id, root.community.id) - onViewMemberMessagesClicked: { - root.rootStore.loadCommunityMemberMessages(root.community.id, pubKey) - Global.openCommunityMemberMessagesPopupRequested(root.rootStore, root.chatCommunitySectionModule, pubKey, displayName) + onKickUserClicked: root.rootStore.removeUserFromCommunity(id) + onBanUserClicked: root.rootStore.banUserFromCommunity(id, deleteAllMessages) + onUnbanUserClicked: root.rootStore.unbanUserFromCommunity(id) + onAcceptRequestToJoin: root.rootStore.acceptRequestToJoinCommunity(id, root.community.id) + onDeclineRequestToJoin: root.rootStore.declineRequestToJoinCommunity(id, root.community.id) + onViewMemberMessagesClicked: { + root.rootStore.loadCommunityMemberMessages(root.community.id, pubKey) + Global.openCommunityMemberMessagesPopupRequested(root.rootStore, root.chatCommunitySectionModule, pubKey, displayName) + } } } - PermissionsSettingsPanel { + // PERMISISONS + Loader { + active: false readonly property int sectionKey: Constants.CommunitySettingsSections.Permissions readonly property string sectionName: qsTr("Permissions") readonly property string sectionIcon: "objects" readonly property bool sectionEnabled: true + + sourceComponent: PermissionsSettingsPanel { + readonly property PermissionsStore permissionsStore: + rootStore.permissionsStore - readonly property PermissionsStore permissionsStore: - rootStore.permissionsStore + permissionsModel: permissionsStore.permissionsModel - permissionsModel: permissionsStore.permissionsModel + // temporary solution to provide icons for assets, similar + // method is used in wallet (constructing filename from asset's + // symbol) and is intended to be replaced by more robust + // solution soon. - // temporary solution to provide icons for assets, similar - // method is used in wallet (constructing filename from asset's - // symbol) and is intended to be replaced by more robust - // solution soon. + assetsModel: rootStore.assetsModel - assetsModel: rootStore.assetsModel + collectiblesModel: rootStore.collectiblesModel + channelsModel: rootStore.chatCommunitySectionModule.model - collectiblesModel: rootStore.collectiblesModel - channelsModel: rootStore.chatCommunitySectionModule.model + ensCommunityPermissionsEnabled: rootStore.ensCommunityPermissionsEnabled - ensCommunityPermissionsEnabled: rootStore.ensCommunityPermissionsEnabled + communityDetails: d.communityDetails - communityDetails: d.communityDetails + onCreatePermissionRequested: + permissionsStore.createPermission(holdings, permissionType, + isPrivate, channels) - onCreatePermissionRequested: - permissionsStore.createPermission(holdings, permissionType, - isPrivate, channels) + onUpdatePermissionRequested: + permissionsStore.editPermission( + key, holdings, permissionType, channels, isPrivate) - onUpdatePermissionRequested: - permissionsStore.editPermission( - key, holdings, permissionType, channels, isPrivate) + onRemovePermissionRequested: + permissionsStore.removePermission(key) - onRemovePermissionRequested: - permissionsStore.removePermission(key) - - onNavigateToMintTokenSettings: { - root.goTo(Constants.CommunitySettingsSections.MintTokens) - mintPanel.openNewTokenForm(isAssetType) + onNavigateToMintTokenSettings: { + root.goTo(Constants.CommunitySettingsSections.MintTokens) + mintPanelLoader.item.openNewTokenForm(isAssetType) + } } } - MintTokensSettingsPanel { - id: mintPanel - + // TOKEN + Loader { + id: mintPanelLoader + active: false readonly property int sectionKey: Constants.CommunitySettingsSections.MintTokens readonly property string sectionName: qsTr("Tokens") readonly property string sectionIcon: "token" readonly property bool sectionEnabled: true - enabledChainIds: root.enabledChainIds - readonly property CommunityTokensStore communityTokensStore: - rootStore.communityTokensStore + sourceComponent: MintTokensSettingsPanel { + enabledChainIds: root.enabledChainIds - // General community props - communityId: root.community.id - communityName: root.community.name - communityLogo: root.community.image - communityColor: root.community.color - sendModalPopup: root.sendModalPopup + readonly property CommunityTokensStore communityTokensStore: + rootStore.communityTokensStore - // User profile props - isOwner: root.isOwner - isAdmin: root.isAdmin - isTokenMasterOwner: root.isTokenMasterOwner + // General community props + communityId: root.community.id + communityName: root.community.name + communityLogo: root.community.image + communityColor: root.community.color + sendModalPopup: root.sendModalPopup - // Owner and TMaster properties - isOwnerTokenDeployed: tokensModelChangesTracker.isOwnerTokenDeployed - isTMasterTokenDeployed: tokensModelChangesTracker.isTMasterTokenDeployed - anyPrivilegedTokenFailed: tokensModelChangesTracker.isOwnerTokenFailed || tokensModelChangesTracker.isTMasterTokenFailed - ownerOrTMasterTokenItemsExist: tokensModelChangesTracker.ownerOrTMasterTokenItemsExist + // User profile props + isOwner: root.isOwner + isAdmin: root.isAdmin + isTokenMasterOwner: root.isTokenMasterOwner - // Models - tokensModel: root.community.communityTokens - membersModel: root.community.members - flatNetworks: communityTokensStore.filteredFlatModel - accounts: root.walletAccountsModel - referenceAssetsBySymbolModel: root.tokensStore.assetsBySymbolModel + // Owner and TMaster properties + isOwnerTokenDeployed: tokensModelChangesTracker.isOwnerTokenDeployed + isTMasterTokenDeployed: tokensModelChangesTracker.isTMasterTokenDeployed + anyPrivilegedTokenFailed: tokensModelChangesTracker.isOwnerTokenFailed || tokensModelChangesTracker.isTMasterTokenFailed + ownerOrTMasterTokenItemsExist: tokensModelChangesTracker.ownerOrTMasterTokenItemsExist - onRegisterDeployFeesSubscriber: d.feesBroker.registerDeployFeesSubscriber(feeSubscriber) + // Models + tokensModel: root.community.communityTokens + membersModel: root.community.members + flatNetworks: communityTokensStore.filteredFlatModel + accounts: root.walletAccountsModel + referenceAssetsBySymbolModel: root.tokensStore.assetsBySymbolModel - onRegisterSelfDestructFeesSubscriber: d.feesBroker.registerSelfDestructFeesSubscriber(feeSubscriber) + onRegisterDeployFeesSubscriber: d.feesBroker.registerDeployFeesSubscriber(feeSubscriber) - onRegisterBurnTokenFeesSubscriber: d.feesBroker.registerBurnFeesSubscriber(feeSubscriber) + onRegisterSelfDestructFeesSubscriber: d.feesBroker.registerSelfDestructFeesSubscriber(feeSubscriber) - onStartTokenHoldersManagement: communityTokensStore.startTokenHoldersManagement(root.community.id, chainId, address) + onRegisterBurnTokenFeesSubscriber: d.feesBroker.registerBurnFeesSubscriber(feeSubscriber) - onStopTokenHoldersManagement: communityTokensStore.stopTokenHoldersManagement() + onStartTokenHoldersManagement: communityTokensStore.startTokenHoldersManagement(root.community.id, chainId, address) - onEnableNetwork: root.enableNetwork(chainId) + onStopTokenHoldersManagement: communityTokensStore.stopTokenHoldersManagement() - onMintCollectible: - communityTokensStore.deployCollectible( - root.community.id, collectibleItem) + onEnableNetwork: root.enableNetwork(chainId) - onMintAsset: - communityTokensStore.deployAsset(root.community.id, assetItem) + onMintCollectible: + communityTokensStore.deployCollectible( + root.community.id, collectibleItem) - onMintOwnerToken: - communityTokensStore.deployOwnerToken( - root.community.id, ownerToken, tMasterToken) + onMintAsset: + communityTokensStore.deployAsset(root.community.id, assetItem) - onRemotelyDestructCollectibles: - communityTokensStore.remoteSelfDestructCollectibles( - root.community.id, walletsAndAmounts, tokenKey, accountAddress) + onMintOwnerToken: + communityTokensStore.deployOwnerToken( + root.community.id, ownerToken, tMasterToken) - onRemotelyDestructAndBan: - communityTokensStore.remotelyDestructAndBan( - root.community.id, contactId, tokenKey, accountAddress) + onRemotelyDestructCollectibles: + communityTokensStore.remoteSelfDestructCollectibles( + root.community.id, walletsAndAmounts, tokenKey, accountAddress) - onRemotelyDestructAndKick: - communityTokensStore.remotelyDestructAndKick( - root.community.id, contactId, tokenKey, accountAddress) + onRemotelyDestructAndBan: + communityTokensStore.remotelyDestructAndBan( + root.community.id, contactId, tokenKey, accountAddress) - onBurnToken: - communityTokensStore.burnToken(root.community.id, tokenKey, amount, accountAddress) + onRemotelyDestructAndKick: + communityTokensStore.remotelyDestructAndKick( + root.community.id, contactId, tokenKey, accountAddress) - onDeleteToken: - communityTokensStore.deleteToken(root.community.id, tokenKey) + onBurnToken: + communityTokensStore.burnToken(root.community.id, tokenKey, amount, accountAddress) - onRefreshToken: - communityTokensStore.refreshToken(tokenKey) + onDeleteToken: + communityTokensStore.deleteToken(root.community.id, tokenKey) - onAirdropToken: { - root.goTo(Constants.CommunitySettingsSections.Airdrops) + onRefreshToken: + communityTokensStore.refreshToken(tokenKey) - // Force a token selection to be airdroped with given amount - airdropPanel.selectToken(tokenKey, amount, type) + onAirdropToken: { + root.goTo(Constants.CommunitySettingsSections.Airdrops) - // Set given addresses as recipients - airdropPanel.addAddresses(addresses) + // Force a token selection to be airdroped with given amount + airdropPanelLoader.item.selectToken(tokenKey, amount, type) + + // Set given addresses as recipients + airdropPanelLoader.item.addAddresses(addresses) + } + + onKickUserRequested: root.rootStore.removeUserFromCommunity(contactId) + onBanUserRequested: root.rootStore.banUserFromCommunity(contactId) } - - onKickUserRequested: root.rootStore.removeUserFromCommunity(contactId) - onBanUserRequested: root.rootStore.banUserFromCommunity(contactId) } - AirdropsSettingsPanel { - id: airdropPanel + // AIRDROPS + Loader { + id: airdropPanelLoader + active: false readonly property int sectionKey: Constants.CommunitySettingsSections.Airdrops readonly property string sectionName: qsTr("Airdrops") readonly property string sectionIcon: "airdrop" readonly property bool sectionEnabled: true - communityDetails: d.communityDetails + sourceComponent: AirdropsSettingsPanel { + id: airdropsSettingsPanel - // Profile type - isOwner: root.isOwner - isTokenMasterOwner: root.isTokenMasterOwner - isAdmin: root.isAdmin + communityDetails: d.communityDetails - // Owner and TMaster properties - isOwnerTokenDeployed: tokensModelChangesTracker.isOwnerTokenDeployed - isTMasterTokenDeployed: tokensModelChangesTracker.isTMasterTokenDeployed + // Profile type + isOwner: root.isOwner + isTokenMasterOwner: root.isTokenMasterOwner + isAdmin: root.isAdmin - readonly property CommunityTokensStore communityTokensStore: - rootStore.communityTokensStore + // Owner and TMaster properties + isOwnerTokenDeployed: tokensModelChangesTracker.isOwnerTokenDeployed + isTMasterTokenDeployed: tokensModelChangesTracker.isTMasterTokenDeployed - readonly property var communityTokens: root.community.communityTokens + readonly property CommunityTokensStore communityTokensStore: + rootStore.communityTokensStore - Loader { - id: assetsModelLoader - active: airdropPanel.communityTokens + readonly property RolesRenamingModel renamedTokensBySymbolModel: RolesRenamingModel { + sourceModel: root.community.communityTokens || null + mapping: [ + RoleRename { + from: "symbol" + to: "key" + }, + RoleRename { + from: "image" + to: "iconSource" + } + ] + } - sourceComponent: SortFilterProxyModel { - - sourceModel: airdropPanel.communityTokens + assetsModel: SortFilterProxyModel { + sourceModel: renamedTokensBySymbolModel filters: ValueFilter { roleName: "tokenType" value: Constants.TokenType.ERC20 } proxyRoles: [ - ExpressionRole { + ConstantRole { name: "category" - - // Singleton cannot be used directly in the expression - readonly property int category: TokenCategories.Category.Own - expression: category + value: TokenCategories.Category.Own }, - ExpressionRole { - name: "iconSource" - expression: model.image - }, - ExpressionRole { - name: "key" - expression: model.symbol - }, - ExpressionRole { + ConstantRole { name: "communityId" - expression: "" + value: "" } ] } - } - - Loader { - id: collectiblesModelLoader - active: airdropPanel.communityTokens - - sourceComponent: SortFilterProxyModel { - - sourceModel: airdropPanel.communityTokens + collectiblesModel: SortFilterProxyModel { + sourceModel: renamedTokensBySymbolModel filters: [ ValueFilter { roleName: "tokenType" value: Constants.TokenType.ERC721 }, - ExpressionFilter { - function getPrivileges(privilegesLevel) { - return privilegesLevel === Constants.TokenPrivilegesLevel.Community || - (root.isOwner && privilegesLevel === Constants.TokenPrivilegesLevel.TMaster) + AnyOf { + ValueFilter { + roleName: "privilegesLevel" + value: Constants.TokenPrivilegesLevel.Community + } + ValueFilter { + roleName: "privilegesLevel" + value: Constants.TokenPrivilegesLevel.TMaster + enabled: root.isOwner } - - expression: { return getPrivileges(model.privilegesLevel) } } ] proxyRoles: [ - ExpressionRole { + ConstantRole { name: "category" - - // Singleton cannot be used directly in the epression - readonly property int category: TokenCategories.Category.Own - expression: category + value: TokenCategories.Category.Own }, - ExpressionRole { - name: "iconSource" - expression: model.image - }, - ExpressionRole { - name: "key" - expression: model.symbol - }, - ExpressionRole { + ConstantRole { name: "communityId" - expression: "" + value: "" } ] } + + Connections { + target: root.rootStore.communityTokensStore + + function onAirdropStateChanged(communityId, tokenName, chainName, status, url) { + if (root.community.id !== communityId) { + return + } + + if (status == Constants.ContractTransactionStatus.InProgress) { + airdropsSettingsPanel.navigateBack() + } + } + } + + membersModel: community.members + enabledChainIds: root.enabledChainIds + onEnableNetwork: root.enableNetwork(chainId) + + accountsModel: root.walletAccountsModel + onAirdropClicked: communityTokensStore.airdrop( + root.community.id, airdropTokens, addresses, + feeAccountAddress) + + onNavigateToMintTokenSettings: { + root.goTo(Constants.CommunitySettingsSections.MintTokens) + mintPanelLoader.item.openNewTokenForm(isAssetType) + } + + onRegisterAirdropFeeSubscriber: d.feesBroker.registerAirdropFeesSubscriber(feeSubscriber) } - - assetsModel: assetsModelLoader.item - collectiblesModel: collectiblesModelLoader.item - membersModel: community.members - enabledChainIds: root.enabledChainIds - onEnableNetwork: root.enableNetwork(chainId) - - accountsModel: root.walletAccountsModel - onAirdropClicked: communityTokensStore.airdrop( - root.community.id, airdropTokens, addresses, - feeAccountAddress) - - onNavigateToMintTokenSettings: { - root.goTo(Constants.CommunitySettingsSections.MintTokens) - mintPanel.openNewTokenForm(isAssetType) - } - - onRegisterAirdropFeeSubscriber: d.feesBroker.registerAirdropFeesSubscriber(feeSubscriber) } } @@ -723,7 +749,6 @@ StatusSectionLayout { case Constants.ContractTransactionStatus.InProgress: title = qsTr("Airdrop on %1 in progress...").arg(chainName) loading = true - airdropPanel.navigateBack() break case Constants.ContractTransactionStatus.Completed: title = qsTr("Airdrop on %1 in complete").arg(chainName) diff --git a/ui/app/AppLayouts/Communities/views/PermissionsView.qml b/ui/app/AppLayouts/Communities/views/PermissionsView.qml index 05ba8ed216..8b773ab811 100644 --- a/ui/app/AppLayouts/Communities/views/PermissionsView.qml +++ b/ui/app/AppLayouts/Communities/views/PermissionsView.qml @@ -43,7 +43,7 @@ ColumnLayout { signal removePermissionRequested(int index) signal userRestrictionsToggled(bool checked) - readonly property alias count: repeater.count + readonly property alias count: listView.count Connections { target: root.communityDetails @@ -58,7 +58,7 @@ ColumnLayout { } } - function resetCommunityItemModel(){ + function resetCommunityItemModel() { communityItemModel.clear() communityItemModel.append({ text: root.communityDetails.name, @@ -87,14 +87,18 @@ ColumnLayout { ] } - - Repeater { - id: repeater - + StatusListView { + id: listView + reuseItems: true model: root.permissionsModel + spacing: 24 + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredHeight: contentHeight + Layout.topMargin: root.topPadding delegate: PermissionItem { - Layout.fillWidth: true + width: root.viewWidth holdingsListModel: HoldingsSelectionModel { sourceModel: model.holdingsListModel @@ -155,6 +159,7 @@ ColumnLayout { root.userRestrictionsToggled(checked); } } + ConfirmationDialog { id: declineAllDialog diff --git a/ui/app/AppLayouts/Profile/panels/ContactsListPanel.qml b/ui/app/AppLayouts/Profile/panels/ContactsListPanel.qml index 47daa4dd76..cf6f6ff2f3 100644 --- a/ui/app/AppLayouts/Profile/panels/ContactsListPanel.qml +++ b/ui/app/AppLayouts/Profile/panels/ContactsListPanel.qml @@ -91,13 +91,6 @@ Item { } } ] - proxyRoles: ExpressionRole { - function displayNameProxy(nickname, ensName, displayName, aliasName) { - return ProfileUtils.displayName(nickname, ensName, displayName, aliasName) - } - name: "preferredDisplayName" - expression: displayNameProxy(model.localNickname, model.ensName, model.displayName, model.alias) - } sorters: [ StringSorter { diff --git a/ui/imports/shared/stores/PermissionsStore.qml b/ui/imports/shared/stores/PermissionsStore.qml index 1846eb3568..48615cd5ff 100644 --- a/ui/imports/shared/stores/PermissionsStore.qml +++ b/ui/imports/shared/stores/PermissionsStore.qml @@ -21,20 +21,6 @@ QtObject { //TODO: backend implementation } - // TODO: Replace with proper backend implementation - // This is per chat, not per community - readonly property bool viewAndPostCriteriaMet: { - if (selectedChannelPermissionsModel.count == 0) - return true - - for (var i = 0; i < selectedChannelPermissionsModel.count; i++) { - var permissionItem = selectedChannelPermissionsModel.get(i); - if (permissionItem && permissionItem.tokenCriteriaMet) - return true - } - return false - } - readonly property var selectedChannelPermissionsModel: SortFilterProxyModel { id: selectedChannelPermissionsModel sourceModel: root.permissionsModel