mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-25 03:06:31 -05:00
feat(frontend): deactivate permissions buttons if user is not owner
These buttons and their functionality only work if the user is the owner, so it doesn't make sense to make it possible to press them otherwise… Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
parent
09e56a418e
commit
e7e81cf670
10 changed files with 107 additions and 28 deletions
|
@ -1,10 +1,11 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { useOnInputChange } from '../../../../hooks/common/use-on-input-change'
|
||||
import { UiIcon } from '../../../common/icons/ui-icon'
|
||||
import type { PermissionDisabledProps } from './permission-disabled.prop'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { Button, FormControl, InputGroup } from 'react-bootstrap'
|
||||
import { Plus as IconPlus } from 'react-bootstrap-icons'
|
||||
|
@ -20,8 +21,13 @@ export interface PermissionAddEntryFieldProps {
|
|||
*
|
||||
* @param onAddEntry Callback that is fired with the entered username as identifier of the entry to add.
|
||||
* @param i18nKey The localization key for the submit button.
|
||||
* @param disabled If the user is not the owner, functionality is disabled.
|
||||
*/
|
||||
export const PermissionAddEntryField: React.FC<PermissionAddEntryFieldProps> = ({ onAddEntry, i18nKey }) => {
|
||||
export const PermissionAddEntryField: React.FC<PermissionAddEntryFieldProps & PermissionDisabledProps> = ({
|
||||
onAddEntry,
|
||||
i18nKey,
|
||||
disabled
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [newEntryIdentifier, setNewEntryIdentifier] = useState('')
|
||||
|
@ -34,8 +40,18 @@ export const PermissionAddEntryField: React.FC<PermissionAddEntryFieldProps> = (
|
|||
return (
|
||||
<li className={'list-group-item'}>
|
||||
<InputGroup className={'me-1 mb-1'}>
|
||||
<FormControl value={newEntryIdentifier} placeholder={t(i18nKey) ?? undefined} onChange={onChange} />
|
||||
<Button variant='light' className={'text-secondary ms-2'} title={t(i18nKey) ?? undefined} onClick={onSubmit}>
|
||||
<FormControl
|
||||
value={newEntryIdentifier}
|
||||
placeholder={t(i18nKey) ?? undefined}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<Button
|
||||
variant='light'
|
||||
className={'text-secondary ms-2'}
|
||||
title={t(i18nKey) ?? undefined}
|
||||
onClick={onSubmit}
|
||||
disabled={disabled}>
|
||||
<UiIcon icon={IconPlus} />
|
||||
</Button>
|
||||
</InputGroup>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export interface PermissionDisabledProps {
|
||||
disabled: boolean
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { UiIcon } from '../../../common/icons/ui-icon'
|
||||
import type { PermissionDisabledProps } from './permission-disabled.prop'
|
||||
import { AccessLevel } from './types'
|
||||
import React, { useMemo } from 'react'
|
||||
import { Button, ToggleButtonGroup } from 'react-bootstrap'
|
||||
|
@ -41,14 +42,16 @@ export interface PermissionEntryButtonsProps {
|
|||
* @param onSetReadOnly Callback that is fired when the entry is changed to read-only permission.
|
||||
* @param onSetWriteable Callback that is fired when the entry is changed to writeable permission.
|
||||
* @param onRemove Callback that is fired when the entry is removed.
|
||||
* @param disabled If the user is not the owner, functionality is disabled.
|
||||
*/
|
||||
export const PermissionEntryButtons: React.FC<PermissionEntryButtonsProps> = ({
|
||||
export const PermissionEntryButtons: React.FC<PermissionEntryButtonsProps & PermissionDisabledProps> = ({
|
||||
name,
|
||||
type,
|
||||
currentSetting,
|
||||
onSetReadOnly,
|
||||
onSetWriteable,
|
||||
onRemove
|
||||
onRemove,
|
||||
disabled
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
|
@ -74,18 +77,21 @@ export const PermissionEntryButtons: React.FC<PermissionEntryButtonsProps> = ({
|
|||
<Button
|
||||
variant='light'
|
||||
className={'text-danger me-2'}
|
||||
disabled={disabled}
|
||||
title={t(i18nKeys.remove, { name }) ?? undefined}
|
||||
onClick={onRemove}>
|
||||
<UiIcon icon={IconX} />
|
||||
</Button>
|
||||
<ToggleButtonGroup type='radio' name='edit-mode' value={currentSetting}>
|
||||
<Button
|
||||
disabled={disabled}
|
||||
title={t(i18nKeys.setReadOnly, { name }) ?? undefined}
|
||||
variant={currentSetting === AccessLevel.READ_ONLY ? 'secondary' : 'outline-secondary'}
|
||||
onClick={onSetReadOnly}>
|
||||
<UiIcon icon={IconEye} />
|
||||
</Button>
|
||||
<Button
|
||||
disabled={disabled}
|
||||
title={t(i18nKeys.setWriteable, { name }) ?? undefined}
|
||||
variant={currentSetting === AccessLevel.WRITEABLE ? 'secondary' : 'outline-secondary'}
|
||||
onClick={onSetWriteable}>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
@ -8,6 +8,7 @@ import { useApplicationState } from '../../../../hooks/common/use-application-st
|
|||
import { setNotePermissionsFromServer } from '../../../../redux/note-details/methods'
|
||||
import { IconButton } from '../../../common/icon-button/icon-button'
|
||||
import { useUiNotifications } from '../../../notifications/ui-notification-boundary'
|
||||
import type { PermissionDisabledProps } from './permission-disabled.prop'
|
||||
import { AccessLevel, SpecialGroup } from './types'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { ToggleButtonGroup } from 'react-bootstrap'
|
||||
|
@ -26,8 +27,13 @@ export interface PermissionEntrySpecialGroupProps {
|
|||
*
|
||||
* @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 disabled If the user is not the owner, functionality is disabled.
|
||||
*/
|
||||
export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupProps> = ({ level, type }) => {
|
||||
export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupProps & PermissionDisabledProps> = ({
|
||||
level,
|
||||
type,
|
||||
disabled
|
||||
}) => {
|
||||
const noteId = useApplicationState((state) => state.noteDetails.primaryAddress)
|
||||
const { t } = useTranslation()
|
||||
const { showErrorNotification } = useUiNotifications()
|
||||
|
@ -75,6 +81,7 @@ export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupPr
|
|||
title={t('editor.modal.permissions.denyGroup', { name }) ?? undefined}
|
||||
variant={level === AccessLevel.NONE ? 'secondary' : 'outline-secondary'}
|
||||
onClick={onSetEntryDenied}
|
||||
disabled={disabled}
|
||||
className={'p-1'}
|
||||
/>
|
||||
<IconButton
|
||||
|
@ -82,6 +89,7 @@ export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupPr
|
|||
title={t('editor.modal.permissions.viewOnlyGroup', { name }) ?? undefined}
|
||||
variant={level === AccessLevel.READ_ONLY ? 'secondary' : 'outline-secondary'}
|
||||
onClick={onSetEntryReadOnly}
|
||||
disabled={disabled}
|
||||
className={'p-1'}
|
||||
/>
|
||||
<IconButton
|
||||
|
@ -89,6 +97,7 @@ export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupPr
|
|||
title={t('editor.modal.permissions.editGroup', { name }) ?? undefined}
|
||||
variant={level === AccessLevel.WRITEABLE ? 'secondary' : 'outline-secondary'}
|
||||
onClick={onSetEntryWriteable}
|
||||
disabled={disabled}
|
||||
className={'p-1'}
|
||||
/>
|
||||
</ToggleButtonGroup>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
@ -11,6 +11,7 @@ import { setNotePermissionsFromServer } from '../../../../redux/note-details/met
|
|||
import { ShowIf } from '../../../common/show-if/show-if'
|
||||
import { UserAvatarForUser } from '../../../common/user-avatar/user-avatar-for-user'
|
||||
import { useUiNotifications } from '../../../notifications/ui-notification-boundary'
|
||||
import type { PermissionDisabledProps } from './permission-disabled.prop'
|
||||
import { PermissionEntryButtons, PermissionType } from './permission-entry-buttons'
|
||||
import { AccessLevel } from './types'
|
||||
import React, { useCallback } from 'react'
|
||||
|
@ -24,8 +25,12 @@ export interface PermissionEntryUserProps {
|
|||
* Permission entry for a user that can be set to read-only or writeable and can be removed.
|
||||
*
|
||||
* @param entry The permission entry.
|
||||
* @param disabled If the user is not the owner, functionality is disabled.
|
||||
*/
|
||||
export const PermissionEntryUser: React.FC<PermissionEntryUserProps> = ({ entry }) => {
|
||||
export const PermissionEntryUser: React.FC<PermissionEntryUserProps & PermissionDisabledProps> = ({
|
||||
entry,
|
||||
disabled
|
||||
}) => {
|
||||
const noteId = useApplicationState((state) => state.noteDetails.primaryAddress)
|
||||
const { showErrorNotification } = useUiNotifications()
|
||||
|
||||
|
@ -72,6 +77,7 @@ export const PermissionEntryUser: React.FC<PermissionEntryUserProps> = ({ entry
|
|||
onSetReadOnly={onSetEntryReadOnly}
|
||||
onSetWriteable={onSetEntryWriteable}
|
||||
onRemove={onRemoveEntry}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</li>
|
||||
</ShowIf>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { useIsOwner } from '../../../../hooks/common/use-is-owner'
|
||||
import type { ModalVisibilityProps } from '../../../common/modals/common-modal'
|
||||
import { CommonModal } from '../../../common/modals/common-modal'
|
||||
import { PermissionSectionOwner } from './permission-section-owner'
|
||||
|
@ -18,12 +19,13 @@ import { Modal } from 'react-bootstrap'
|
|||
* @param onHide Callback that is fired when the modal is about to be closed.
|
||||
*/
|
||||
export const PermissionModal: React.FC<ModalVisibilityProps> = ({ show, onHide }) => {
|
||||
const isOwner = useIsOwner()
|
||||
return (
|
||||
<CommonModal show={show} onHide={onHide} showCloseButton={true} titleI18nKey={'editor.modal.permissions.title'}>
|
||||
<Modal.Body>
|
||||
<PermissionSectionOwner />
|
||||
<PermissionSectionUsers />
|
||||
<PermissionSectionSpecialGroups />
|
||||
<PermissionSectionOwner disabled={!isOwner} />
|
||||
<PermissionSectionUsers disabled={!isOwner} />
|
||||
<PermissionSectionSpecialGroups disabled={!isOwner} />
|
||||
</Modal.Body>
|
||||
</CommonModal>
|
||||
)
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { useApplicationState } from '../../../../hooks/common/use-application-state'
|
||||
import { UiIcon } from '../../../common/icons/ui-icon'
|
||||
import { UserAvatarForUsername } from '../../../common/user-avatar/user-avatar-for-username'
|
||||
import type { PermissionDisabledProps } from './permission-disabled.prop'
|
||||
import React, { Fragment } from 'react'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import { Pencil as IconPencil } from 'react-bootstrap-icons'
|
||||
|
@ -19,8 +20,12 @@ export interface PermissionOwnerInfoProps {
|
|||
* Content for the owner section of the permission modal that shows the current note owner.
|
||||
*
|
||||
* @param onEditOwner Callback that is fired when the user chooses to change the note owner.
|
||||
* @param disabled If the user is not the owner, functionality is disabled.
|
||||
*/
|
||||
export const PermissionOwnerInfo: React.FC<PermissionOwnerInfoProps> = ({ onEditOwner }) => {
|
||||
export const PermissionOwnerInfo: React.FC<PermissionOwnerInfoProps & PermissionDisabledProps> = ({
|
||||
onEditOwner,
|
||||
disabled
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const noteOwner = useApplicationState((state) => state.noteDetails.permissions.owner)
|
||||
|
||||
|
@ -29,6 +34,7 @@ export const PermissionOwnerInfo: React.FC<PermissionOwnerInfoProps> = ({ onEdit
|
|||
<UserAvatarForUsername username={noteOwner} />
|
||||
<Button
|
||||
variant='light'
|
||||
disabled={disabled}
|
||||
title={t('editor.modal.permissions.ownerChange.button') ?? undefined}
|
||||
onClick={onEditOwner}>
|
||||
<UiIcon icon={IconPencil} />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
@ -7,6 +7,7 @@ import { setNoteOwner } from '../../../../api/permissions'
|
|||
import { useApplicationState } from '../../../../hooks/common/use-application-state'
|
||||
import { setNotePermissionsFromServer } from '../../../../redux/note-details/methods'
|
||||
import { useUiNotifications } from '../../../notifications/ui-notification-boundary'
|
||||
import type { PermissionDisabledProps } from './permission-disabled.prop'
|
||||
import { PermissionOwnerChange } from './permission-owner-change'
|
||||
import { PermissionOwnerInfo } from './permission-owner-info'
|
||||
import React, { Fragment, useCallback, useState } from 'react'
|
||||
|
@ -14,8 +15,10 @@ import { Trans } from 'react-i18next'
|
|||
|
||||
/**
|
||||
* Section in the permissions modal for managing the owner of a note.
|
||||
*
|
||||
* @param disabled If the user is not the owner, functionality is disabled.
|
||||
*/
|
||||
export const PermissionSectionOwner: React.FC = () => {
|
||||
export const PermissionSectionOwner: React.FC<PermissionDisabledProps> = ({ disabled }) => {
|
||||
const noteId = useApplicationState((state) => state.noteDetails.primaryAddress)
|
||||
const [changeOwner, setChangeOwner] = useState(false)
|
||||
const { showErrorNotification } = useUiNotifications()
|
||||
|
@ -48,7 +51,7 @@ export const PermissionSectionOwner: React.FC = () => {
|
|||
{changeOwner ? (
|
||||
<PermissionOwnerChange onConfirmOwnerChange={onOwnerChange} />
|
||||
) : (
|
||||
<PermissionOwnerInfo onEditOwner={onSetChangeOwner} />
|
||||
<PermissionOwnerInfo onEditOwner={onSetChangeOwner} disabled={disabled} />
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { useApplicationState } from '../../../../hooks/common/use-application-state'
|
||||
import { useIsOwner } from '../../../../hooks/common/use-is-owner'
|
||||
import type { PermissionDisabledProps } from './permission-disabled.prop'
|
||||
import { PermissionEntrySpecialGroup } from './permission-entry-special-group'
|
||||
import { AccessLevel, SpecialGroup } from './types'
|
||||
import React, { Fragment, useMemo } from 'react'
|
||||
|
@ -11,10 +13,13 @@ import { Trans, useTranslation } from 'react-i18next'
|
|||
|
||||
/**
|
||||
* Section of the permission modal for managing special group access to the note.
|
||||
*
|
||||
* @param disabled If the user is not the owner, functionality is disabled.
|
||||
*/
|
||||
export const PermissionSectionSpecialGroups: React.FC = () => {
|
||||
export const PermissionSectionSpecialGroups: React.FC<PermissionDisabledProps> = ({ disabled }) => {
|
||||
useTranslation()
|
||||
const groupPermissions = useApplicationState((state) => state.noteDetails.permissions.sharedToGroups)
|
||||
const isOwner = useIsOwner()
|
||||
|
||||
const specialGroupEntries = useMemo(() => {
|
||||
const groupEveryone = groupPermissions.find((entry) => entry.groupName === SpecialGroup.EVERYONE)
|
||||
|
@ -40,8 +45,16 @@ export const PermissionSectionSpecialGroups: React.FC = () => {
|
|||
<Trans i18nKey={'editor.modal.permissions.sharedWithElse'} />
|
||||
</h5>
|
||||
<ul className={'list-group'}>
|
||||
<PermissionEntrySpecialGroup level={specialGroupEntries.loggedIn} type={SpecialGroup.LOGGED_IN} />
|
||||
<PermissionEntrySpecialGroup level={specialGroupEntries.everyone} type={SpecialGroup.EVERYONE} />
|
||||
<PermissionEntrySpecialGroup
|
||||
level={specialGroupEntries.loggedIn}
|
||||
type={SpecialGroup.LOGGED_IN}
|
||||
disabled={!isOwner}
|
||||
/>
|
||||
<PermissionEntrySpecialGroup
|
||||
level={specialGroupEntries.everyone}
|
||||
type={SpecialGroup.EVERYONE}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</ul>
|
||||
</Fragment>
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
@ -8,22 +8,27 @@ import { useApplicationState } from '../../../../hooks/common/use-application-st
|
|||
import { setNotePermissionsFromServer } from '../../../../redux/note-details/methods'
|
||||
import { useUiNotifications } from '../../../notifications/ui-notification-boundary'
|
||||
import { PermissionAddEntryField } from './permission-add-entry-field'
|
||||
import type { PermissionDisabledProps } from './permission-disabled.prop'
|
||||
import { PermissionEntryUser } from './permission-entry-user'
|
||||
import React, { Fragment, useCallback, useMemo } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
|
||||
/**
|
||||
* Section of the permission modal for managing user access to the note.
|
||||
*
|
||||
* @param disabled If the user is not the owner, functionality is disabled.
|
||||
*/
|
||||
export const PermissionSectionUsers: React.FC = () => {
|
||||
export const PermissionSectionUsers: React.FC<PermissionDisabledProps> = ({ disabled }) => {
|
||||
useTranslation()
|
||||
const userPermissions = useApplicationState((state) => state.noteDetails.permissions.sharedToUsers)
|
||||
const noteId = useApplicationState((state) => state.noteDetails.primaryAddress)
|
||||
const { showErrorNotification } = useUiNotifications()
|
||||
|
||||
const userEntries = useMemo(() => {
|
||||
return userPermissions.map((entry) => <PermissionEntryUser key={entry.username} entry={entry} />)
|
||||
}, [userPermissions])
|
||||
return userPermissions.map((entry) => (
|
||||
<PermissionEntryUser key={entry.username} entry={entry} disabled={disabled} />
|
||||
))
|
||||
}, [userPermissions, disabled])
|
||||
|
||||
const onAddEntry = useCallback(
|
||||
(username: string) => {
|
||||
|
@ -43,7 +48,11 @@ export const PermissionSectionUsers: React.FC = () => {
|
|||
</h5>
|
||||
<ul className={'list-group'}>
|
||||
{userEntries}
|
||||
<PermissionAddEntryField onAddEntry={onAddEntry} i18nKey={'editor.modal.permissions.addUser'} />
|
||||
<PermissionAddEntryField
|
||||
onAddEntry={onAddEntry}
|
||||
i18nKey={'editor.modal.permissions.addUser'}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</ul>
|
||||
</Fragment>
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue