status-desktop/ui/app/AppLayouts/Communities/panels/PermissionsSettingsPanel.qml

351 lines
13 KiB
QML
Raw Normal View History

import QtQuick 2.15
import QtQuick.Controls 2.15
import AppLayouts.Communities.controls 1.0
import AppLayouts.Communities.layouts 1.0
import AppLayouts.Communities.views 1.0
fix(permissions): fix hang when all channel perm check return (#14259) * fix(permissions): fix hang when all channel perm check return Fixes #14234 The problem was that we updated **all** the models from **all** the channels of a community each time the channel requirement checks returned. The fix is to first of all, make sure we don't call that check too often. It sometimes got called twice in a row by accident. The other better fix is to check if anything actually changed before updating. This solves the issue almost entirely. Since the permissions almost never change, the updates now take only a second. * fix(permisisons): never run permission checks for privileged users Also fixes #14234 but for admins, TMs and Owners. Admins+ were still getting the hang, because the permission checks always returned something different than the models, because the models knew that admins have access to everything, but the permission check was running as if it were a normal user (I think, un-tested). Anyway, the solution is more simple, we never need to run the permission checks on admins+, because they always have access to everything! * fix(Communities): prevent channels model from emitting unnecessary signals Closes: #14274 * chore(Communities): improve channels metadata lookup performance ChannelsSelectionModel is removed, replaced with plain LeftJoinModel. Transformations of left-side model are done in a single place, not in every delegate making the join. * only call update functions when there is something to update + move permission model creation when needed --------- Co-authored-by: Michał Cieślak <michalcieslak@status.im>
2024-04-04 15:26:44 +00:00
import StatusQ 0.1
import StatusQ.Controls 0.1
fix(permissions): fix hang when all channel perm check return (#14259) * fix(permissions): fix hang when all channel perm check return Fixes #14234 The problem was that we updated **all** the models from **all** the channels of a community each time the channel requirement checks returned. The fix is to first of all, make sure we don't call that check too often. It sometimes got called twice in a row by accident. The other better fix is to check if anything actually changed before updating. This solves the issue almost entirely. Since the permissions almost never change, the updates now take only a second. * fix(permisisons): never run permission checks for privileged users Also fixes #14234 but for admins, TMs and Owners. Admins+ were still getting the hang, because the permission checks always returned something different than the models, because the models knew that admins have access to everything, but the permission check was running as if it were a normal user (I think, un-tested). Anyway, the solution is more simple, we never need to run the permission checks on admins+, because they always have access to everything! * fix(Communities): prevent channels model from emitting unnecessary signals Closes: #14274 * chore(Communities): improve channels metadata lookup performance ChannelsSelectionModel is removed, replaced with plain LeftJoinModel. Transformations of left-side model are done in a single place, not in every delegate making the join. * only call update functions when there is something to update + move permission model creation when needed --------- Co-authored-by: Michał Cieślak <michalcieslak@status.im>
2024-04-04 15:26:44 +00:00
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1
import utils 1.0
import shared.popups 1.0
fix(permissions): fix hang when all channel perm check return (#14259) * fix(permissions): fix hang when all channel perm check return Fixes #14234 The problem was that we updated **all** the models from **all** the channels of a community each time the channel requirement checks returned. The fix is to first of all, make sure we don't call that check too often. It sometimes got called twice in a row by accident. The other better fix is to check if anything actually changed before updating. This solves the issue almost entirely. Since the permissions almost never change, the updates now take only a second. * fix(permisisons): never run permission checks for privileged users Also fixes #14234 but for admins, TMs and Owners. Admins+ were still getting the hang, because the permission checks always returned something different than the models, because the models knew that admins have access to everything, but the permission check was running as if it were a normal user (I think, un-tested). Anyway, the solution is more simple, we never need to run the permission checks on admins+, because they always have access to everything! * fix(Communities): prevent channels model from emitting unnecessary signals Closes: #14274 * chore(Communities): improve channels metadata lookup performance ChannelsSelectionModel is removed, replaced with plain LeftJoinModel. Transformations of left-side model are done in a single place, not in every delegate making the join. * only call update functions when there is something to update + move permission model creation when needed --------- Co-authored-by: Michał Cieślak <michalcieslak@status.im>
2024-04-04 15:26:44 +00:00
import SortFilterProxyModel 0.2
StackView {
id: root
required property var permissionsModel
required property var assetsModel
required property var collectiblesModel
required property var channelsModel
property bool showChannelSelector: true
property bool ensCommunityPermissionsEnabled
property alias initialPage: initialItem
// id, name, image, color, owner properties expected
required property var communityDetails
property int viewWidth: 560 // by design
property string previousPageName: depth > 1 ? qsTr("Permissions") : ""
signal createPermissionRequested(int permissionType, var holdings,
var channels, bool isPrivate)
signal updatePermissionRequested(string key, int permissionType,
var holdings, var channels, bool isPrivate)
signal removePermissionRequested(string key)
signal navigateToMintTokenSettings(bool isAssetType)
function navigateBack() {
if (depth === 2 && currentItem.toast.active)
currentItem.toast.notifyDirty()
else
pop(StackView.Immediate)
}
function pushEditView(properties) {
root.push(newPermissionView, properties, StackView.Immediate);
}
fix(permissions): fix hang when all channel perm check return (#14259) * fix(permissions): fix hang when all channel perm check return Fixes #14234 The problem was that we updated **all** the models from **all** the channels of a community each time the channel requirement checks returned. The fix is to first of all, make sure we don't call that check too often. It sometimes got called twice in a row by accident. The other better fix is to check if anything actually changed before updating. This solves the issue almost entirely. Since the permissions almost never change, the updates now take only a second. * fix(permisisons): never run permission checks for privileged users Also fixes #14234 but for admins, TMs and Owners. Admins+ were still getting the hang, because the permission checks always returned something different than the models, because the models knew that admins have access to everything, but the permission check was running as if it were a normal user (I think, un-tested). Anyway, the solution is more simple, we never need to run the permission checks on admins+, because they always have access to everything! * fix(Communities): prevent channels model from emitting unnecessary signals Closes: #14274 * chore(Communities): improve channels metadata lookup performance ChannelsSelectionModel is removed, replaced with plain LeftJoinModel. Transformations of left-side model are done in a single place, not in every delegate making the join. * only call update functions when there is something to update + move permission model creation when needed --------- Co-authored-by: Michał Cieślak <michalcieslak@status.im>
2024-04-04 15:26:44 +00:00
SortFilterProxyModel {
id: allChannelsTransformed
sourceModel: root.channelsModel
proxyRoles: [
FastExpressionRole {
name: "key"
expression: model.itemId ?? ""
expectedRoles: ["itemId"]
},
FastExpressionRole {
name: "text"
expression: "#" + model.name
expectedRoles: ["name"]
},
FastExpressionRole {
name: "imageSource"
expression: model.icon
expectedRoles: ["icon"]
},
FastExpressionRole {
name: "operator"
// Direct call for singleton enum is not handled properly by SortFilterProxyModel.
readonly property int none: OperatorsUtils.Operators.None
expression: none
expectedRoles: []
}
]
}
// Community Permissions possible view contents:
initialItem: SettingsPage {
id: initialItem
width: root.viewWidth + leftPadding
title: qsTr("Permissions")
buttons: StatusButton {
objectName: "addNewItemButton"
text: qsTr("Add new permission")
onClicked: root.push(newPermissionView, StackView.Immediate)
}
contentItem: PermissionsView {
id: permissionsView
permissionsModel: root.permissionsModel
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
channelsModel: allChannelsTransformed
communityDetails: root.communityDetails
viewWidth: root.viewWidth
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);
}
onDuplicatePermissionRequested: {
const item = ModelUtils.get(root.permissionsModel, index)
const properties = {
holdingsToEditModel: item.holdingsListModel,
channelsToEditModel: item.channelsListModel,
permissionTypeToEdit: item.permissionType,
isPrivateToEditValue: item.isPrivate
}
root.pushEditView(properties);
}
onRemovePermissionRequested: {
const key = ModelUtils.get(root.permissionsModel, index, "key")
root.removePermissionRequested(key)
}
}
}
Component {
id: newPermissionView
SettingsPage {
id: newPermissionViewPage
implicitWidth: 0
title: isEditState ? qsTr("Edit permission") : qsTr("New permission")
property alias isSaveEnabled: editPermissionView.saveEnabled
property alias isPrivateToEditValue: editPermissionView.isPrivate
property alias permissionTypeToEdit: editPermissionView.permissionType
property alias holdingsToEditModel: editPermissionView.selectedHoldingsModel
property alias channelsToEditModel: editPermissionView.selectedChannelsModel
property bool holdingsRequired: editPermissionView.dirtyValues.holdingsRequired
property string permissionKeyToEdit
readonly property bool isEditState: !!permissionKeyToEdit
readonly property alias toast: settingsDirtyToastMessage
function resetChanges() {
editPermissionView.resetChanges();
}
function updatePermission() {
editPermissionView.saveChanges();
}
function createPermission() {
editPermissionView.createPermissionClicked();
}
contentItem: EditPermissionView {
id: editPermissionView
viewWidth: root.viewWidth
SortFilterProxyModel {
id: nonOwnerCollectibles
sourceModel: root.collectiblesModel
filters: [
ValueFilter {
roleName: "privilegesLevel"
value: Constants.TokenPrivilegesLevel.Owner
inverted: true
}
]
}
assetsModel: root.assetsModel
collectiblesModel: nonOwnerCollectibles
fix(permissions): fix hang when all channel perm check return (#14259) * fix(permissions): fix hang when all channel perm check return Fixes #14234 The problem was that we updated **all** the models from **all** the channels of a community each time the channel requirement checks returned. The fix is to first of all, make sure we don't call that check too often. It sometimes got called twice in a row by accident. The other better fix is to check if anything actually changed before updating. This solves the issue almost entirely. Since the permissions almost never change, the updates now take only a second. * fix(permisisons): never run permission checks for privileged users Also fixes #14234 but for admins, TMs and Owners. Admins+ were still getting the hang, because the permission checks always returned something different than the models, because the models knew that admins have access to everything, but the permission check was running as if it were a normal user (I think, un-tested). Anyway, the solution is more simple, we never need to run the permission checks on admins+, because they always have access to everything! * fix(Communities): prevent channels model from emitting unnecessary signals Closes: #14274 * chore(Communities): improve channels metadata lookup performance ChannelsSelectionModel is removed, replaced with plain LeftJoinModel. Transformations of left-side model are done in a single place, not in every delegate making the join. * only call update functions when there is something to update + move permission model creation when needed --------- Co-authored-by: Michał Cieślak <michalcieslak@status.im>
2024-04-04 15:26:44 +00:00
channelsModel: allChannelsTransformed
communityDetails: root.communityDetails
showChannelSelector: root.showChannelSelector
isEditState: newPermissionViewPage.isEditState
ensCommunityPermissionsEnabled: root.ensCommunityPermissionsEnabled
holdingsRequired: selectedHoldingsModel
? selectedHoldingsModel.count > 0 : false
permissionDuplicated: {
// dependencies
holdingsTracker.revision
channelsTracker.revision
editPermissionView.dirtyValues.permissionType
editPermissionView.dirtyValues.isPrivate
const model = root.permissionsModel
const count = model.rowCount()
for (let i = 0; i < count; i++) {
const item = ModelUtils.get(model, i)
if (newPermissionViewPage.permissionKeyToEdit === item.key)
continue
const holdings = item.holdingsListModel
const channels = item.channelsListModel
const permissionType = item.permissionType
const same = (a, b) => ModelUtils.checkEqualitySet(a, b, ["key"])
if (holdings.rowCount() === 0)
if (dirtyValues.holdingsRequired)
continue
else
return true
if (holdings.rowCount() !== 0 && !dirtyValues.holdingsRequired)
continue
const channelsModel = showChannelSelector ?
dirtyValues.selectedChannelsModel :
selectedChannelsModel
if (same(dirtyValues.selectedHoldingsModel, holdings)
&& same(channelsModel, channels)
&& dirtyValues.permissionType === permissionType)
return true
}
return false
}
readonly property var permissionTypeLimitReachedOrExceeded: {
const type = dirtyValues.permissionType
const limit = PermissionTypes.getPermissionsCountLimit(type)
if (limit === -1)
return [false, false]
const model = root.permissionsModel
const count = model.rowCount()
let sameTypeCount = 0
for (let i = 0; i < count; i++)
if (type === ModelUtils.get(model, i, "permissionType"))
sameTypeCount++
return [sameTypeCount >= limit, sameTypeCount > limit]
}
permissionTypeLimitReached: permissionTypeLimitReachedOrExceeded[0]
permissionTypeLimitExceeded: permissionTypeLimitReachedOrExceeded[1]
onCreatePermissionClicked: {
const holdings = dirtyValues.holdingsRequired ?
ModelUtils.modelToArray(
dirtyValues.selectedHoldingsModel,
["key", "type", "amount", "symbol"]) : []
const channels = root.showChannelSelector ?
ModelUtils.modelToArray(
dirtyValues.selectedChannelsModel, ["key"]) :
ModelUtils.modelToArray(selectedChannelsModel, ["key"])
root.createPermissionRequested(
dirtyValues.permissionType, holdings, channels,
dirtyValues.isPrivate)
if (root.showChannelSelector) {
root.pop(StackView.Immediate)
}
}
onNavigateToMintTokenSettings: root.navigateToMintTokenSettings(isAssetType)
function saveChanges() {
const holdings = dirtyValues.holdingsRequired ?
ModelUtils.modelToArray(
dirtyValues.selectedHoldingsModel,
["key", "type", "amount", "symbol"])
: []
const channels = ModelUtils.modelToArray(
dirtyValues.selectedChannelsModel, ["key"])
root.updatePermissionRequested(
newPermissionViewPage.permissionKeyToEdit,
dirtyValues.permissionType, holdings, channels,
dirtyValues.isPrivate)
}
ModelChangeTracker {
id: holdingsTracker
model: editPermissionView.dirtyValues.selectedHoldingsModel
}
ModelChangeTracker {
id: channelsTracker
model: editPermissionView.dirtyValues.selectedChannelsModel
}
}
SettingsDirtyToastMessage {
id: settingsDirtyToastMessage
z: 1
anchors {
bottom: parent.bottom
horizontalCenter: parent.horizontalCenter
bottomMargin: 16
}
saveChangesText: qsTr("Update permission")
cancelChangesText: qsTr("Revert changes")
saveChangesButtonEnabled: editPermissionView.saveEnabled
onSaveChangesClicked: {
editPermissionView.saveChanges()
root.pop(StackView.Immediate)
}
onResetChangesClicked: editPermissionView.resetChanges()
Component.onCompleted: {
// delay to avoid toast blinking on entry
settingsDirtyToastMessage.active = Qt.binding(
() => editPermissionView.isEditState &&
editPermissionView.dirty &&
root.showChannelSelector)
}
}
}
}
}