From 59048b2069d97014e313191ff03b83374586564a Mon Sep 17 00:00:00 2001 From: Patryk Osmaczko Date: Tue, 31 Oct 2023 21:40:00 +0100 Subject: [PATCH] feat(communities): integrate community sharding closes: #12408 --- .../modules/main/chat_section/controller.nim | 14 ++++++ .../main/chat_section/io_interface.nim | 9 +++- src/app/modules/main/chat_section/module.nim | 7 +++ src/app/modules/main/chat_section/view.nim | 23 ++++++++- src/app/modules/main/module.nim | 3 ++ .../modules/shared_models/section_item.nim | 27 +++++++++++ .../modules/shared_models/section_model.nim | 15 ++++++ src/app_service/common/types.nim | 10 +++- src/app_service/service/chat/dto/chat.nim | 13 +++++ .../service/community/async_tasks.nim | 21 ++++++++ .../service/community/dto/community.nim | 16 +++++++ src/app_service/service/community/service.nim | 35 ++++++++++++++ src/backend/communities.nim | 18 +++++++ storybook/pages/EditSettingsPanelPage.qml | 12 +++-- storybook/pages/EnableShardingPopupPage.qml | 26 ++++++---- storybook/pages/ManageShardingPopupPage.qml | 2 +- storybook/pages/OverviewSettingsPanelPage.qml | 6 +-- .../Communities/panels/EditSettingsPanel.qml | 48 +++++++++++-------- .../panels/OverviewSettingsPanel.qml | 21 +++++--- .../popups/EnableShardingPopup.qml | 34 ++++++------- .../popups/ManageShardingPopup.qml | 4 +- .../views/CommunitySettingsView.qml | 12 +++-- 22 files changed, 305 insertions(+), 71 deletions(-) diff --git a/src/app/modules/main/chat_section/controller.nim b/src/app/modules/main/chat_section/controller.nim index 53ff18dead..fe5544dbef 100644 --- a/src/app/modules/main/chat_section/controller.nim +++ b/src/app/modules/main/chat_section/controller.nim @@ -333,6 +333,16 @@ proc init*(self: Controller) = if (args.communityId == self.sectionId): self.delegate.onAcceptRequestToJoinFailedNoPermission(args.communityId, args.pubKey, args.requestId) + self.events.on(SIGNAL_COMMUNITY_SHARD_SET) do(e: Args): + let args = CommunityShardSetArgs(e) + if args.communityId == self.sectionId: + self.delegate.setShardingInProgress(false) + + self.events.on(SIGNAL_COMMUNITY_SHARD_SET_FAILED) do(e: Args): + let args = CommunityShardSetArgs(e) + if args.communityId == self.sectionId: + self.delegate.setShardingInProgress(false) + self.events.on(SIGNAL_CONTACT_NICKNAME_CHANGED) do(e: Args): var args = ContactArgs(e) self.delegate.onContactDetailsUpdated(args.contactId) @@ -685,3 +695,7 @@ proc collectCommunityMetricsMessagesCount*(self: Controller, intervals: string) proc waitingOnNewCommunityOwnerToConfirmRequestToRejoin*(self: Controller, communityId: string): bool = self.communityService.waitingOnNewCommunityOwnerToConfirmRequestToRejoin(communityId) + +proc setCommunityShard*(self: Controller, shardIndex: int) = + self.communityService.asyncSetCommunityShard(self.getMySectionId(), shardIndex) + diff --git a/src/app/modules/main/chat_section/io_interface.nim b/src/app/modules/main/chat_section/io_interface.nim index bf8a810590..e447b7e604 100644 --- a/src/app/modules/main/chat_section/io_interface.nim +++ b/src/app/modules/main/chat_section/io_interface.nim @@ -407,4 +407,11 @@ method getChannelsPermissionsCheckOngoing*(self: AccessInterface): bool {.base.} raise newException(ValueError, "No implementation available") method onWaitingOnNewCommunityOwnerToConfirmRequestToRejoin*(self: AccessInterface) {.base.} = - raise newException(ValueError, "No implementation available") \ No newline at end of file + raise newException(ValueError, "No implementation available") + +method setCommunityShard*(self: AccessInterface, shardIndex: int) {.base.} = + raise newException(ValueError, "No implementation available") + +method setShardingInProgress*(self: AccessInterface, value: bool) {.base.} = + raise newException(ValueError, "No implementation available") + diff --git a/src/app/modules/main/chat_section/module.nim b/src/app/modules/main/chat_section/module.nim index ee2eabdf7b..f9704ebe73 100644 --- a/src/app/modules/main/chat_section/module.nim +++ b/src/app/modules/main/chat_section/module.nim @@ -1349,3 +1349,10 @@ method setChannelsPermissionsCheckOngoing*(self: Module, value: bool) = method onWaitingOnNewCommunityOwnerToConfirmRequestToRejoin*(self: Module) = self.view.setWaitingOnNewCommunityOwnerToConfirmRequestToRejoin(true) + +method setCommunityShard*(self: Module, shardIndex: int) = + self.controller.setCommunityShard(shardIndex) + +method setShardingInProgress*(self: Module, value: bool) = + self.view.setShardingInProgress(value) + diff --git a/src/app/modules/main/chat_section/view.nim b/src/app/modules/main/chat_section/view.nim index 53f1d16ec5..36a29f39c7 100644 --- a/src/app/modules/main/chat_section/view.nim +++ b/src/app/modules/main/chat_section/view.nim @@ -30,6 +30,7 @@ QtObject: communityMetrics: string # NOTE: later this should be replaced with QAbstractListModel-based model permissionsCheckOngoing: bool isWaitingOnNewCommunityOwnerToConfirmRequestToRejoin: bool + shardingInProgress: bool proc delete*(self: View) = self.model.delete @@ -462,4 +463,24 @@ QtObject: QtProperty[bool] isWaitingOnNewCommunityOwnerToConfirmRequestToRejoin: read = getWaitingOnNewCommunityOwnerToConfirmRequestToRejoin - notify = isWaitingOnNewCommunityOwnerToConfirmRequestToRejoinChanged \ No newline at end of file + notify = isWaitingOnNewCommunityOwnerToConfirmRequestToRejoinChanged + + proc getShardingInProgress*(self: View): bool {.slot.} = + return self.shardingInProgress + + proc shardingInProgressChanged*(self: View) {.signal.} + + QtProperty[bool] shardingInProgress: + read = getShardingInProgress + notify = shardingInProgressChanged + + proc setShardingInProgress*(self: View, value: bool) = + if (value == self.shardingInProgress): + return + self.shardingInProgress = value + self.shardingInProgressChanged() + + proc setCommunityShard*(self: View, shardIndex: int) {.slot.} = + self.setShardingInProgress(true) + self.delegate.setCommunityShard(shardIndex) + diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index 800f68de3a..62cc71bb86 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -433,6 +433,9 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto): ) else: @[], channelGroup.encrypted, communityTokensItems, + channelGroup.pubsubTopic, + channelGroup.pubsubTopicKey, + channelGroup.shard.index, ) proc connectForNotificationsOnly[T](self: Module[T]) = diff --git a/src/app/modules/shared_models/section_item.nim b/src/app/modules/shared_models/section_item.nim index 03304a3e7a..21e48fefb8 100644 --- a/src/app/modules/shared_models/section_item.nim +++ b/src/app/modules/shared_models/section_item.nim @@ -57,6 +57,9 @@ type declinedMemberRequestsModel: member_model.Model encrypted: bool communityTokensModel: community_tokens_model.TokenModel + pubsubTopic: string + pubsubTopicKey: string + shardIndex: int proc initItem*( id: string, @@ -94,6 +97,9 @@ proc initItem*( declinedMemberRequests: seq[MemberItem] = @[], encrypted: bool = false, communityTokens: seq[TokenItem] = @[], + pubsubTopic = "", + pubsubTopicKey = "", + shardIndex = -1, ): SectionItem = result.id = id result.sectionType = sectionType @@ -136,6 +142,9 @@ proc initItem*( result.encrypted = encrypted result.communityTokensModel = newTokenModel() result.communityTokensModel.setItems(communityTokens) + result.pubsubTopic = pubsubTopic + result.pubsubTopicKey = pubsubTopicKey + result.shardIndex = shardIndex proc isEmpty*(self: SectionItem): bool = return self.id.len == 0 @@ -366,3 +375,21 @@ proc updateMembershipStatus*(self: SectionItem, memberKey: string, status: Membe self.bannedMembersModel.updateMembershipStatus(memberKey, status) else: self.membersModel.updateMembershipStatus(memberKey, status) + +proc pubsubTopic*(self: SectionItem): string {.inline.} = + self.pubsubTopic + +proc `pubsubTopic=`*(self: var SectionItem, value: string) {.inline.} = + self.pubsubTopic = value + +proc pubsubTopicKey*(self: SectionItem): string {.inline.} = + self.pubsubTopicKey + +proc `pubsubTopicKey=`*(self: var SectionItem, value: string) {.inline.} = + self.pubsubTopicKey = value + +proc shardIndex*(self: SectionItem): int {.inline.} = + self.shardIndex + +proc `shardIndex=`*(self: var SectionItem, value: int) {.inline.} = + self.shardIndex = value diff --git a/src/app/modules/shared_models/section_model.nim b/src/app/modules/shared_models/section_model.nim index 6cd1770540..4ede12ee3b 100644 --- a/src/app/modules/shared_models/section_model.nim +++ b/src/app/modules/shared_models/section_model.nim @@ -43,6 +43,9 @@ type PendingMemberRequestsModel DeclinedMemberRequestsModel AmIBanned + PubsubTopic + PubsubTopicKey + ShardIndex QtObject: type @@ -116,6 +119,9 @@ QtObject: ModelRole.PendingMemberRequestsModel.int:"pendingMemberRequests", ModelRole.DeclinedMemberRequestsModel.int:"declinedMemberRequests", ModelRole.AmIBanned.int:"amIBanned", + ModelRole.PubsubTopic.int:"pubsubTopic", + ModelRole.PubsubTopicKey.int:"pubsubTopicKey", + ModelRole.ShardIndex.int:"shardIndex", }.toTable method data(self: SectionModel, index: QModelIndex, role: int): QVariant = @@ -201,6 +207,12 @@ QtObject: result = newQVariant(item.declinedMemberRequests) of ModelRole.AmIBanned: result = newQVariant(item.amIBanned) + of ModelRole.PubsubTopic: + result = newQVariant(item.pubsubTopic) + of ModelRole.PubsubTopicKey: + result = newQVariant(item.pubsubTopicKey) + of ModelRole.ShardIndex: + result = newQVariant(item.shardIndex) proc itemExists*(self: SectionModel, id: string): bool = for it in self.items: @@ -415,6 +427,9 @@ QtObject: "ensOnly": item.ensOnly, "nbMembers": item.members.getCount(), "encrypted": item.encrypted, + "pubsubTopic": item.pubsubTopic, + "pubsubTopicKey": item.pubsubTopicKey, + "shardIndex": item.shardIndex, } return $jsonObj diff --git a/src/app_service/common/types.nim b/src/app_service/common/types.nim index 4f50a51211..2ed3ec166e 100644 --- a/src/app_service/common/types.nim +++ b/src/app_service/common/types.nim @@ -74,4 +74,12 @@ type ContractTransactionStatus* {.pure.} = enum Failed, InProgress, - Completed \ No newline at end of file + Completed + +type Shard* = object + cluster*: int + index*: int + +proc initShard*(cluster: int = -1, index: int = -1): Shard = + result.cluster = cluster + result.index = index \ No newline at end of file diff --git a/src/app_service/service/chat/dto/chat.nim b/src/app_service/service/chat/dto/chat.nim index b6b485c630..5ddb8dc388 100644 --- a/src/app_service/service/chat/dto/chat.nim +++ b/src/app_service/service/chat/dto/chat.nim @@ -113,6 +113,9 @@ type ChannelGroupDto* = object unviewedMessagesCount*: int unviewedMentionsCount*: int channelPermissions*: CheckAllChannelsPermissionsResponseDto + pubsubTopic*: string + pubsubTopicKey*: string + shard*: Shard type ClearedHistoryDto* = object chatId*: string @@ -374,6 +377,16 @@ proc toChannelGroupDto*(jsonObj: JsonNode): ChannelGroupDto = for channelId, permissionResponse in checkChannelPermissionResponsesObj: result.channelPermissions.channels[channelId] = permissionResponse.toCheckChannelPermissionsResponseDto() + discard jsonObj.getProp("pubsubTopic", result.pubsubTopic) + discard jsonObj.getProp("pubsubTopicKey", result.pubsubTopicKey) + + var shardObj: JsonNode + if(jsonObj.getProp("shard", shardObj)): + var shard = initShard() + discard shardObj.getProp("cluster", shard.cluster) + discard shardObj.getProp("index", shard.index) + result.shard = shard + # To parse Community chats to ChatDto, we need to add the commuity ID and type proc toChatDto*(jsonObj: JsonNode, communityId: string): ChatDto = result = jsonObj.toChatDto() diff --git a/src/app_service/service/community/async_tasks.nim b/src/app_service/service/community/async_tasks.nim index 245906e268..940faff41f 100644 --- a/src/app_service/service/community/async_tasks.nim +++ b/src/app_service/service/community/async_tasks.nim @@ -292,3 +292,24 @@ const asyncReevaluateCommunityMembersPermissionsTask: Task = proc(argEncoded: st "communityId": arg.communityId, "error": e.msg, }) + + +type + AsyncSetCommunityShardArg = ref object of QObjectTaskArg + communityId: string + shardIndex: int + +const asyncSetCommunityShardTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncSetCommunityShardArg](argEncoded) + try: + let response = status_go.setCommunityShard(arg.communityId, arg.shardIndex) + arg.finish(%* { + "communityId": arg.communityId, + "response": response, + "error": "", + }) + except Exception as e: + arg.finish(%* { + "communityId": arg.communityId, + "error": e.msg, + }) diff --git a/src/app_service/service/community/dto/community.nim b/src/app_service/service/community/dto/community.nim index f182cdcfaf..2fdaab8bf0 100644 --- a/src/app_service/service/community/dto/community.nim +++ b/src/app_service/service/community/dto/community.nim @@ -170,6 +170,9 @@ type CommunityDto* = object communityTokensMetadata*: seq[CommunityTokensMetadataDto] channelPermissions*: CheckAllChannelsPermissionsResponseDto activeMembersCount*: int64 + pubsubTopic*: string + pubsubTopicKey*: string + shard*: Shard proc isAvailable*(communityDto: CommunityDto): bool = return communityDto.name != "" and communityDto.description != "" @@ -455,6 +458,16 @@ proc toCommunityDto*(jsonObj: JsonNode): CommunityDto = for tokenObj in communityTokensMetadataObj: result.communityTokensMetadata.add(tokenObj.toCommunityTokensMetadataDto()) + discard jsonObj.getProp("pubsubTopic", result.pubsubTopic) + discard jsonObj.getProp("pubsubTopicKey", result.pubsubTopicKey) + + var shardObj: JsonNode + if(jsonObj.getProp("shard", shardObj)): + var shard = initShard() + discard shardObj.getProp("cluster", shard.cluster) + discard shardObj.getProp("index", shard.index) + result.shard = shard + proc toMembershipRequestState*(state: CommunityMemberPendingBanOrKick): MembershipRequestState = case state: of CommunityMemberPendingBanOrKick.Banned: @@ -550,6 +563,9 @@ proc toChannelGroupDto*(communityDto: CommunityDto): ChannelGroupDto = historyArchiveSupportEnabled: communityDto.settings.historyArchiveSupportEnabled, bannedMembersIds: communityDto.getBannedMembersIds(), encrypted: communityDto.encrypted, + shard: communityDto.shard, + pubsubTopic: communityDto.pubsubTopic, + pubsubTopicKey: communityDto.pubsubTopicKey, ) proc parseCommunitiesSettings*(response: JsonNode): seq[CommunitySettingsDto] = diff --git a/src/app_service/service/community/service.nim b/src/app_service/service/community/service.nim index ae14f5dfe5..d3897ea735 100644 --- a/src/app_service/service/community/service.nim +++ b/src/app_service/service/community/service.nim @@ -146,6 +146,9 @@ type memberPubkey*: string status*: MembershipRequestState + CommunityShardSetArgs* = ref object of Args + communityId*: string + # Signals which may be emitted by this service: const SIGNAL_COMMUNITY_DATA_LOADED* = "communityDataLoaded" const SIGNAL_COMMUNITY_JOINED* = "communityJoined" @@ -220,6 +223,9 @@ const SIGNAL_CHECK_PERMISSIONS_TO_JOIN_FAILED* = "checkPermissionsToJoinFailed" const SIGNAL_COMMUNITY_METRICS_UPDATED* = "communityMetricsUpdated" +const SIGNAL_COMMUNITY_SHARD_SET* = "communityShardSet" +const SIGNAL_COMMUNITY_SHARD_SET_FAILED* = "communityShardSetFailed" + QtObject: type Service* = ref object of QObject @@ -2258,3 +2264,32 @@ QtObject: except Exception as e: error "error while reevaluating community members permissions", msg = e.msg + + proc asyncSetCommunityShard*(self: Service, communityId: string, shardIndex: int) = + try: + let arg = AsyncSetCommunityShardArg( + tptr: cast[ByteAddress](asyncSetCommunityShardTask), + vptr: cast[ByteAddress](self.vptr), + slot: "onAsyncSetCommunityShardDone", + communityId: communityId, + shardIndex: shardIndex, + ) + self.threadpool.start(arg) + except Exception as e: + error "Error request to join community", msg = e.msg + + proc onAsyncSetCommunityShardDone*(self: Service, communityIdAndRpcResponse: string) {.slot.} = + let rpcResponseObj = communityIdAndRpcResponse.parseJson + try: + if (rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != ""): + raise newException(CatchableError, rpcResponseObj{"error"}.getStr) + + let rpcResponse = Json.decode($rpcResponseObj["response"], RpcResponse[JsonNode]) + let community = rpcResponse.result["communities"][0].toCommunityDto() + + self.handleCommunityUpdates(@[community], @[], @[]) + self.events.emit(SIGNAL_COMMUNITY_SHARD_SET, CommunityShardSetArgs(communityId: rpcResponseObj["communityId"].getStr)) + + except Exception as e: + error "Error setting community shard", msg = e.msg + self.events.emit(SIGNAL_COMMUNITY_SHARD_SET_FAILED, CommunityShardSetArgs(communityId: rpcResponseObj["communityId"].getStr)) diff --git a/src/backend/communities.nim b/src/backend/communities.nim index 039514c78b..443a586f72 100644 --- a/src/backend/communities.nim +++ b/src/backend/communities.nim @@ -496,3 +496,21 @@ proc getCommunityMembersForWalletAddresses*(communityId: string, chainId: int): proc promoteSelfToControlNode*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} = return callPrivateRPC("promoteSelfToControlNode".prefix, %* [communityId]) + +proc setCommunityShard*(communityId: string, index: int): RpcResponse[JsonNode] {.raises: [Exception].} = + let mainStatusShardClusterID = 16 + if index != -1: + result = callPrivateRPC("setCommunityShard".prefix, %*[ + { + "communityId": communityId, + "shard": { + "cluster": mainStatusShardClusterID, + "index": index + }, + }]) + else: # unset community shard + result = callPrivateRPC("setCommunityShard".prefix, %*[ + { + "communityId": communityId, + }]) + diff --git a/storybook/pages/EditSettingsPanelPage.qml b/storybook/pages/EditSettingsPanelPage.qml index 042cd6d53f..3dcf4d2215 100644 --- a/storybook/pages/EditSettingsPanelPage.qml +++ b/storybook/pages/EditSettingsPanelPage.qml @@ -17,6 +17,7 @@ SplitView { } EditSettingsPanel { + id: panel SplitView.fillWidth: true SplitView.fillHeight: true name: communityEditor.name @@ -24,10 +25,13 @@ SplitView { logoImageData: communityEditor.image description: communityEditor.description bannerImageData: communityEditor.banner - communityId: "0xdeadbeef" - communityShardingEnabled: communityEditor.shardingEnabled - communityShardIndex: communityEditor.shardIndex - onCommunityShardIndexChanged: communityEditor.shardIndex = communityShardIndex + shardingEnabled: communityEditor.shardingEnabled + shardIndex: communityEditor.shardIndex + onShardIndexEdited: { + panel.shardingInProgress = true + communityEditor.shardIndex = shardIndex + panel.shardingInProgress = false + } } ScrollView { diff --git a/storybook/pages/EnableShardingPopupPage.qml b/storybook/pages/EnableShardingPopupPage.qml index d03d9f0efe..81806a2b9d 100644 --- a/storybook/pages/EnableShardingPopupPage.qml +++ b/storybook/pages/EnableShardingPopupPage.qml @@ -35,9 +35,22 @@ SplitView { closePolicy: Popup.NoAutoClose communityName: "Foobar" - publicKey: "0xdeadbeef" - shardingInProgress: ctrlShardingInProgress.checked - onEnableSharding: logs.logEvent("enableSharding", ["shardIndex"], arguments) + shardIndex: -1 + pubsubTopic: '{"pubsubTopic":"/waku/2/rs/16/%1", "publicKey":"0xdeadbeef"}'.arg(dialog.shardIndex) + + onShardIndexChanged: { + shardingInProgress = true + logs.logEvent("enableSharding", ["shardIndex"], arguments) + shardSetterDelayer.start() + } + } + + Timer { + id: shardSetterDelayer + interval: 1000 + onTriggered: { + dialog.shardingInProgress = false + } } } @@ -46,13 +59,6 @@ SplitView { SplitView.preferredHeight: 200 logsView.logText: logs.logText - - ColumnLayout { - Switch { - id: ctrlShardingInProgress - text: "Sharding in progress" - } - } } } diff --git a/storybook/pages/ManageShardingPopupPage.qml b/storybook/pages/ManageShardingPopupPage.qml index d15acf62c5..7148619787 100644 --- a/storybook/pages/ManageShardingPopupPage.qml +++ b/storybook/pages/ManageShardingPopupPage.qml @@ -37,7 +37,7 @@ SplitView { communityName: "Foobar" shardIndex: 33 - pubSubTopic: '{"pubsubTopic":"/waku/2/rs/16/%1", "publicKey":"%2"}'.arg(shardIndex).arg("0xdeadbeef") + pubsubTopic: '{"pubsubTopic":"/waku/2/rs/16/%1", "publicKey":"%2"}'.arg(shardIndex).arg("0xdeadbeef") onDisableShardingRequested: logs.logEvent("ManageShardingPopup::disableShardingRequested") onEditShardIndexRequested: logs.logEvent("ManageShardingPopup::editShardIndexRequested") diff --git a/storybook/pages/OverviewSettingsPanelPage.qml b/storybook/pages/OverviewSettingsPanelPage.qml index b81c75a5f1..594ca1b3d0 100644 --- a/storybook/pages/OverviewSettingsPanelPage.qml +++ b/storybook/pages/OverviewSettingsPanelPage.qml @@ -22,9 +22,9 @@ SplitView { isOwner: communityEditor.amISectionAdmin communitySettingsDisabled: !editable - communityShardingEnabled: communityEditor.shardingEnabled - communityShardIndex: communityEditor.shardIndex - + shardingEnabled: communityEditor.shardingEnabled + shardIndex: communityEditor.shardIndex + isPendingOwnershipRequest: pendingOwnershipSwitch.checked finaliseOwnershipTransferPopup: undefined } diff --git a/ui/app/AppLayouts/Communities/panels/EditSettingsPanel.qml b/ui/app/AppLayouts/Communities/panels/EditSettingsPanel.qml index 3d12004dd9..be19bbc8b5 100644 --- a/ui/app/AppLayouts/Communities/panels/EditSettingsPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/EditSettingsPanel.qml @@ -23,9 +23,12 @@ StatusScrollView { property alias tags: baseLayout.tags property alias selectedTags: baseLayout.selectedTags property alias options: baseLayout.options - property string communityId - property bool communityShardingEnabled - property int communityShardIndex: -1 + + property bool shardingEnabled + property int shardIndex + property bool shardingInProgress + property string pubsubTopic + property string pubsubTopicKey property alias logoImageData: baseLayout.logoImageData property alias logoImagePath: baseLayout.logoImagePath @@ -42,6 +45,8 @@ StatusScrollView { (introMessageTextInput.input.dirty && !introMessageTextInput.valid) || (outroMessageTextInput.input.dirty && !outroMessageTextInput.valid)) + signal shardIndexEdited(int shardIndex) + padding: 0 ColumnLayout { @@ -75,14 +80,14 @@ StatusScrollView { Layout.fillWidth: true Layout.topMargin: -baseLayout.spacing Layout.bottomMargin: 2 - visible: root.communityShardingEnabled + visible: root.shardingEnabled } RowLayout { spacing: Style.current.halfPadding - visible: root.communityShardingEnabled + visible: root.shardingEnabled - readonly property bool shardingActive: root.communityShardIndex !== -1 + readonly property bool shardingActive: root.shardIndex !== -1 StatusBaseText { Layout.fillWidth: true @@ -92,11 +97,12 @@ StatusScrollView { StatusBaseText { color: Theme.palette.baseColor1 visible: parent.shardingActive - text: qsTr("Active: on shard #%1").arg(root.communityShardIndex) + text: qsTr("Active: on shard #%1").arg(root.shardIndex) } StatusButton { size: StatusBaseButton.Size.Small text: parent.shardingActive ? qsTr("Manage") : qsTr("Make %1 a sharded community").arg(root.name) + loading: root.shardingInProgress onClicked: parent.shardingActive ? Global.openPopup(manageShardingPopupCmp) : Global.openPopup(enableShardingPopupCmp) } } @@ -111,13 +117,17 @@ StatusScrollView { Component { id: enableShardingPopupCmp EnableShardingPopup { + id: enableShardingPopup destroyOnClose: true communityName: root.name - publicKey: root.communityId - shardingInProgress: false // TODO community sharding backend: set to "true" when generating the pubSub topic, or migrating - onEnableSharding: { - console.warn("TODO: enable community sharding for shardIndex:", shardIndex) // TODO community sharding backend - root.communityShardIndex = shardIndex + shardIndex: root.shardIndex + pubsubTopic: '{"pubsubTopic":"%1", "publicKey":"%2"}'.arg(root.pubsubTopic).arg(root.pubsubTopicKey) + shardingInProgress: root.shardingInProgress + + onShardIndexChanged: root.shardIndexEdited(shardIndex) + onShardingInProgressChanged: if (!shardingInProgress) { + // bring back the binding + enableShardingPopup.shardIndex = Qt.binding(() => root.shardIndex) } } } @@ -125,16 +135,14 @@ StatusScrollView { Component { id: manageShardingPopupCmp ManageShardingPopup { + id: manageShardingPopup destroyOnClose: true communityName: root.name - shardIndex: root.communityShardIndex - pubSubTopic: '{"pubsubTopic":"/waku/2/rs/16/%1", "publicKey":"%2"}'.arg(shardIndex).arg(root.communityId) // TODO community sharding backend - onDisableShardingRequested: { - root.communityShardIndex = -1 // TODO community sharding backend - } - onEditShardIndexRequested: { - Global.openPopup(enableShardingPopupCmp, {initialShardIndex: root.communityShardIndex}) - } + shardIndex: root.shardIndex + pubsubTopic: '{"pubsubTopic":"%1", "publicKey":"%2"}'.arg(root.pubsubTopic).arg(root.pubsubTopicKey) + + onDisableShardingRequested: root.shardIndexEdited(-1) + onEditShardIndexRequested: Global.openPopup(enableShardingPopupCmp) } } } diff --git a/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml b/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml index 505a941cb4..4e18d68e58 100644 --- a/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml @@ -50,9 +50,12 @@ StackLayout { property string overviewChartData: "" - property bool communityShardingEnabled - property int communityShardIndex: -1 - + property bool shardingEnabled + property int shardIndex: -1 + property bool shardingInProgress + property string pubsubTopic + property string pubsubTopicKey + // Community transfer ownership related props: required property var finaliseOwnershipTransferPopup required property bool isPendingOwnershipRequest @@ -74,6 +77,8 @@ StackLayout { signal importControlNodeClicked signal mintOwnerTokenClicked + signal shardIndexEdited(int shardIndex) + clip: true Component { @@ -289,9 +294,11 @@ StackLayout { pinMessagesEnabled: root.pinMessagesEnabled } - communityId: root.communityId - communityShardingEnabled: root.communityShardingEnabled - communityShardIndex: root.communityShardIndex + shardingEnabled: root.shardingEnabled + shardIndex: root.shardIndex + shardingInProgress: root.shardingInProgress + pubsubTopic: root.pubsubTopic + pubsubTopicKey: root.pubsubTopicKey bottomReservedSpace: Qt.size(settingsDirtyToastMessage.implicitWidth, @@ -305,6 +312,8 @@ StackLayout { property: "bottomMargin" value: 24 } + + onShardIndexEdited: root.shardIndexEdited(shardIndex) } } diff --git a/ui/app/AppLayouts/Communities/popups/EnableShardingPopup.qml b/ui/app/AppLayouts/Communities/popups/EnableShardingPopup.qml index a9a4a5a874..3f9bf3cee4 100644 --- a/ui/app/AppLayouts/Communities/popups/EnableShardingPopup.qml +++ b/ui/app/AppLayouts/Communities/popups/EnableShardingPopup.qml @@ -16,22 +16,21 @@ StatusStackModal { id: root required property string communityName - required property string publicKey - property int initialShardIndex: -1 + required property int shardIndex + required property string pubsubTopic property bool shardingInProgress - signal enableSharding(int shardIndex) - stackTitle: qsTr("Enable community sharding for %1").arg(communityName) width: 640 readonly property var cancelButton: StatusFlatButton { + visible: typeof(currentItem.canGoNext) == "undefined" || currentItem.cancellable text: qsTr("Cancel") onClicked: root.close() } nextButton: StatusButton { - text: qsTr("Next") + text: qsTr("Enable community sharding") enabled: typeof(currentItem.canGoNext) == "undefined" || currentItem.canGoNext loading: root.shardingInProgress onClicked: { @@ -39,38 +38,34 @@ StatusStackModal { if (typeof(nextAction) == "function") { return nextAction() } - root.currentIndex++ } } finishButton: StatusButton { - text: qsTr("Enable community sharding") + text: qsTr("Close") enabled: typeof(currentItem.canGoNext) == "undefined" || currentItem.canGoNext onClicked: { - root.enableSharding(d.shardIndex) + root.currentIndex = 0 root.close() } } rightButtons: [cancelButton, nextButton, finishButton] - QtObject { - id: d - readonly property string pubSubTopic: '{"pubsubTopic":"/waku/2/rs/16/%1", "publicKey":"%2"}'.arg(shardIndex).arg(root.publicKey) // FIXME backend - property int shardIndex: root.initialShardIndex - } - onAboutToShow: shardIndexEdit.focus = true + onShardingInProgressChanged: if (!root.shardingInProgress && root.currentIndex == 0) { + root.currentIndex++ + } stackItems: [ ColumnLayout { id: firstPage spacing: Style.current.halfPadding - readonly property bool canGoNext: shardIndexEdit.valid + readonly property bool cancellable: true + readonly property bool canGoNext: shardIndexEdit.valid && root.shardIndex != parseInt(shardIndexEdit.text) readonly property var nextAction: function () { - d.shardIndex = parseInt(shardIndexEdit.text) - root.currentIndex++ + root.shardIndex = parseInt(shardIndexEdit.text) } StatusInput { @@ -78,7 +73,7 @@ StatusStackModal { Layout.fillWidth: true label: qsTr("Enter shard number") placeholderText: qsTr("Enter a number between 0 and 1023") - text: d.shardIndex !== -1 ? d.shardIndex : "" + text: root.shardIndex !== -1 ? root.shardIndex : "" validators: [ StatusIntValidator { bottom: 0 @@ -97,6 +92,7 @@ StatusStackModal { } }, ColumnLayout { + readonly property bool cancellable: false readonly property bool canGoNext: agreement.checked StatusBaseText { @@ -107,7 +103,7 @@ StatusStackModal { Layout.fillWidth: true Layout.preferredHeight: 138 readOnly: true - text: d.pubSubTopic + text: root.pubsubTopic rightPadding: 48 wrapMode: TextEdit.Wrap diff --git a/ui/app/AppLayouts/Communities/popups/ManageShardingPopup.qml b/ui/app/AppLayouts/Communities/popups/ManageShardingPopup.qml index a2b55d2e0c..8d6c7edeb8 100644 --- a/ui/app/AppLayouts/Communities/popups/ManageShardingPopup.qml +++ b/ui/app/AppLayouts/Communities/popups/ManageShardingPopup.qml @@ -19,7 +19,7 @@ StatusDialog { required property string communityName required property int shardIndex - required property string pubSubTopic + required property string pubsubTopic signal disableShardingRequested() signal editShardIndexRequested() @@ -66,7 +66,7 @@ StatusDialog { Layout.fillWidth: true Layout.preferredHeight: 138 readOnly: true - text: root.pubSubTopic + text: root.pubsubTopic rightPadding: 48 wrapMode: TextEdit.Wrap diff --git a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml index 23637afe7d..95d510a605 100644 --- a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml +++ b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml @@ -184,8 +184,11 @@ StatusSectionLayout { isControlNode: root.isControlNode communitySettingsDisabled: root.communitySettingsDisabled overviewChartData: rootStore.overviewChartData - communityShardingEnabled: localAppSettings.wakuV2ShardedCommunitiesEnabled ?? false - communityShardIndex: root.community.shardIndex ?? -1 // TODO community sharding backend + shardingEnabled: localAppSettings.wakuV2ShardedCommunitiesEnabled ?? false + shardIndex: root.community.shardIndex + shardingInProgress: root.chatCommunitySectionModule.shardingInProgress + pubsubTopic: root.community.pubsubTopic + pubsubTopicKey: root.community.pubsubTopicKey sendModalPopup: root.sendModalPopup tokensModel: root.community.communityTokens @@ -245,6 +248,9 @@ StatusSectionLayout { mintPanel.openNewTokenForm(false/*Collectible owner token*/) } + onShardIndexEdited: if (root.community.shardIndex != shardIndex) { + root.chatCommunitySectionModule.setCommunityShard(shardIndex) + } } MembersSettingsPanel { @@ -507,7 +513,7 @@ StatusSectionLayout { onAirdropClicked: communityTokensStore.airdrop( root.community.id, airdropTokens, addresses, feeAccountAddress) - + onNavigateToMintTokenSettings: { root.goTo(Constants.CommunitySettingsSections.MintTokens) mintPanel.openNewTokenForm(isAssetType)