mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-21 17:26:29 -05:00
enhancement(permissions): show alert when permission is overridden by another
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
parent
626a6c7426
commit
dfcf662a85
5 changed files with 64 additions and 18 deletions
|
@ -423,7 +423,8 @@
|
||||||
"error": "There was an error changing the owner of this note.",
|
"error": "There was an error changing the owner of this note.",
|
||||||
"placeholder": "Enter username of new note owner",
|
"placeholder": "Enter username of new note owner",
|
||||||
"button": "Change the owner of this note"
|
"button": "Change the owner of this note"
|
||||||
}
|
},
|
||||||
|
"inconsistent": "This permission is overridden by another permission"
|
||||||
},
|
},
|
||||||
"shareLink": {
|
"shareLink": {
|
||||||
"title": "Share link",
|
"title": "Share link",
|
||||||
|
|
|
@ -15,10 +15,12 @@ import React, { useCallback, useMemo } from 'react'
|
||||||
import { ToggleButtonGroup } from 'react-bootstrap'
|
import { ToggleButtonGroup } from 'react-bootstrap'
|
||||||
import { Eye as IconEye, Pencil as IconPencil, SlashCircle as IconSlashCircle } from 'react-bootstrap-icons'
|
import { Eye as IconEye, Pencil as IconPencil, SlashCircle as IconSlashCircle } from 'react-bootstrap-icons'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { PermissionInconsistentAlert } from './permission-inconsistent-alert'
|
||||||
|
|
||||||
export interface PermissionEntrySpecialGroupProps {
|
export interface PermissionEntrySpecialGroupProps {
|
||||||
level: AccessLevel
|
level: AccessLevel
|
||||||
type: SpecialGroup
|
type: SpecialGroup
|
||||||
|
inconsistent?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,11 +29,13 @@ export interface PermissionEntrySpecialGroupProps {
|
||||||
* @param level The access level that is currently set for the group.
|
* @param level The access level that is currently set for the group.
|
||||||
* @param type The type of the special group. Must be either {@link SpecialGroup.EVERYONE} or {@link SpecialGroup.LOGGED_IN}.
|
* @param type The type of the special group. Must be either {@link SpecialGroup.EVERYONE} or {@link SpecialGroup.LOGGED_IN}.
|
||||||
* @param disabled If the user is not the owner, functionality is disabled.
|
* @param disabled If the user is not the owner, functionality is disabled.
|
||||||
|
* @param inconsistent Whether to show the inconsistency alert icon or not
|
||||||
*/
|
*/
|
||||||
export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupProps & PermissionDisabledProps> = ({
|
export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupProps & PermissionDisabledProps> = ({
|
||||||
level,
|
level,
|
||||||
type,
|
type,
|
||||||
disabled
|
disabled,
|
||||||
|
inconsistent
|
||||||
}) => {
|
}) => {
|
||||||
const noteId = useApplicationState((state) => state.noteDetails?.primaryAddress)
|
const noteId = useApplicationState((state) => state.noteDetails?.primaryAddress)
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
@ -88,6 +92,7 @@ export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupPr
|
||||||
<li className={'list-group-item d-flex flex-row justify-content-between align-items-center'}>
|
<li className={'list-group-item d-flex flex-row justify-content-between align-items-center'}>
|
||||||
<span>{name}</span>
|
<span>{name}</span>
|
||||||
<div>
|
<div>
|
||||||
|
<PermissionInconsistentAlert show={inconsistent ?? false} />
|
||||||
<ToggleButtonGroup type='radio' name='edit-mode'>
|
<ToggleButtonGroup type='radio' name='edit-mode'>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={IconSlashCircle}
|
icon={IconSlashCircle}
|
||||||
|
|
|
@ -13,9 +13,10 @@ import { useUiNotifications } from '../../../../../notifications/ui-notification
|
||||||
import type { PermissionDisabledProps } from './permission-disabled.prop'
|
import type { PermissionDisabledProps } from './permission-disabled.prop'
|
||||||
import { PermissionEntryButtons, PermissionType } from './permission-entry-buttons'
|
import { PermissionEntryButtons, PermissionType } from './permission-entry-buttons'
|
||||||
import type { NoteUserPermissionEntry } from '@hedgedoc/commons'
|
import type { NoteUserPermissionEntry } from '@hedgedoc/commons'
|
||||||
import { AccessLevel } from '@hedgedoc/commons'
|
import { AccessLevel, SpecialGroup } from '@hedgedoc/commons'
|
||||||
import React, { useCallback } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { useAsync } from 'react-use'
|
import { useAsync } from 'react-use'
|
||||||
|
import { PermissionInconsistentAlert } from './permission-inconsistent-alert'
|
||||||
|
|
||||||
export interface PermissionEntryUserProps {
|
export interface PermissionEntryUserProps {
|
||||||
entry: NoteUserPermissionEntry
|
entry: NoteUserPermissionEntry
|
||||||
|
@ -33,6 +34,16 @@ export const PermissionEntryUser: React.FC<PermissionEntryUserProps & Permission
|
||||||
}) => {
|
}) => {
|
||||||
const noteId = useApplicationState((state) => state.noteDetails?.primaryAddress)
|
const noteId = useApplicationState((state) => state.noteDetails?.primaryAddress)
|
||||||
const { showErrorNotification } = useUiNotifications()
|
const { showErrorNotification } = useUiNotifications()
|
||||||
|
const groupPermissions = useApplicationState((state) => state.noteDetails.permissions.sharedToGroups)
|
||||||
|
|
||||||
|
const permissionInconsistent = useMemo(() => {
|
||||||
|
const everyonePermission = groupPermissions.find((group) => group.groupName === (SpecialGroup.EVERYONE as string))
|
||||||
|
const loggedInPermission = groupPermissions.find((group) => group.groupName === (SpecialGroup.LOGGED_IN as string))
|
||||||
|
return (
|
||||||
|
(everyonePermission && everyonePermission.canEdit && !entry.canEdit) ||
|
||||||
|
(loggedInPermission && loggedInPermission.canEdit && !entry.canEdit)
|
||||||
|
)
|
||||||
|
}, [groupPermissions, entry])
|
||||||
|
|
||||||
const onRemoveEntry = useCallback(() => {
|
const onRemoveEntry = useCallback(() => {
|
||||||
if (!noteId) {
|
if (!noteId) {
|
||||||
|
@ -79,15 +90,18 @@ export const PermissionEntryUser: React.FC<PermissionEntryUserProps & Permission
|
||||||
<ShowIf condition={!loading && !error}>
|
<ShowIf condition={!loading && !error}>
|
||||||
<li className={'list-group-item d-flex flex-row justify-content-between align-items-center'}>
|
<li className={'list-group-item d-flex flex-row justify-content-between align-items-center'}>
|
||||||
<UserAvatarForUser user={value} />
|
<UserAvatarForUser user={value} />
|
||||||
<PermissionEntryButtons
|
<div className={'d-flex flex-row align-items-center'}>
|
||||||
type={PermissionType.USER}
|
<PermissionInconsistentAlert show={permissionInconsistent ?? false} />
|
||||||
currentSetting={entry.canEdit ? AccessLevel.WRITEABLE : AccessLevel.READ_ONLY}
|
<PermissionEntryButtons
|
||||||
name={value.displayName}
|
type={PermissionType.USER}
|
||||||
onSetReadOnly={onSetEntryReadOnly}
|
currentSetting={entry.canEdit ? AccessLevel.WRITEABLE : AccessLevel.READ_ONLY}
|
||||||
onSetWriteable={onSetEntryWriteable}
|
name={value.displayName}
|
||||||
onRemove={onRemoveEntry}
|
onSetReadOnly={onSetEntryReadOnly}
|
||||||
disabled={disabled}
|
onSetWriteable={onSetEntryWriteable}
|
||||||
/>
|
onRemove={onRemoveEntry}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ShowIf>
|
</ShowIf>
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
import React from 'react'
|
||||||
|
import { UiIcon } from '../../../../../common/icons/ui-icon'
|
||||||
|
import { ExclamationTriangleFill as IconExclamationTriangleFill } from 'react-bootstrap-icons'
|
||||||
|
import type { SimpleAlertProps } from '../../../../../common/simple-alert/simple-alert-props'
|
||||||
|
import { useTranslatedText } from '../../../../../../hooks/common/use-translated-text'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alert that is shown when the permissions are inconsistent.
|
||||||
|
*
|
||||||
|
* @param show true to show the alert, false otherwise.
|
||||||
|
*/
|
||||||
|
export const PermissionInconsistentAlert: React.FC<SimpleAlertProps> = ({ show }) => {
|
||||||
|
const message = useTranslatedText('editor.modal.permissions.inconsistent')
|
||||||
|
|
||||||
|
if (!show) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return <UiIcon icon={IconExclamationTriangleFill} className={'text-warning me-2'} title={message} />
|
||||||
|
}
|
|
@ -29,16 +29,17 @@ export const PermissionSectionSpecialGroups: React.FC<PermissionDisabledProps> =
|
||||||
const groupLoggedIn = groupPermissions.find((entry) => entry.groupName === (SpecialGroup.LOGGED_IN as string))
|
const groupLoggedIn = groupPermissions.find((entry) => entry.groupName === (SpecialGroup.LOGGED_IN as string))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
everyone: groupEveryone
|
everyoneLevel: groupEveryone
|
||||||
? groupEveryone.canEdit
|
? groupEveryone.canEdit
|
||||||
? AccessLevel.WRITEABLE
|
? AccessLevel.WRITEABLE
|
||||||
: AccessLevel.READ_ONLY
|
: AccessLevel.READ_ONLY
|
||||||
: AccessLevel.NONE,
|
: AccessLevel.NONE,
|
||||||
loggedIn: groupLoggedIn
|
loggedInLevel: groupLoggedIn
|
||||||
? groupLoggedIn.canEdit
|
? groupLoggedIn.canEdit
|
||||||
? AccessLevel.WRITEABLE
|
? AccessLevel.WRITEABLE
|
||||||
: AccessLevel.READ_ONLY
|
: AccessLevel.READ_ONLY
|
||||||
: AccessLevel.NONE
|
: AccessLevel.NONE,
|
||||||
|
loggedInInconsistentAlert: groupEveryone && (!groupLoggedIn || (groupEveryone.canEdit && !groupLoggedIn.canEdit))
|
||||||
}
|
}
|
||||||
}, [groupPermissions])
|
}, [groupPermissions])
|
||||||
|
|
||||||
|
@ -53,12 +54,13 @@ export const PermissionSectionSpecialGroups: React.FC<PermissionDisabledProps> =
|
||||||
</h5>
|
</h5>
|
||||||
<ul className={'list-group'}>
|
<ul className={'list-group'}>
|
||||||
<PermissionEntrySpecialGroup
|
<PermissionEntrySpecialGroup
|
||||||
level={specialGroupEntries.loggedIn}
|
level={specialGroupEntries.loggedInLevel}
|
||||||
type={SpecialGroup.LOGGED_IN}
|
type={SpecialGroup.LOGGED_IN}
|
||||||
disabled={!isOwner}
|
disabled={!isOwner}
|
||||||
|
inconsistent={specialGroupEntries.loggedInInconsistentAlert}
|
||||||
/>
|
/>
|
||||||
<PermissionEntrySpecialGroup
|
<PermissionEntrySpecialGroup
|
||||||
level={specialGroupEntries.everyone}
|
level={specialGroupEntries.everyoneLevel}
|
||||||
type={SpecialGroup.EVERYONE}
|
type={SpecialGroup.EVERYONE}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Reference in a new issue