mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
R: Replace AccessMode with RoleStore
Some checks are pending
Frontend CI / build (22.x) (push) Waiting to run
Some checks are pending
Frontend CI / build (22.x) (push) Waiting to run
This commit is contained in:
parent
b9ee1b9d08
commit
b260640ebf
|
@ -1,25 +0,0 @@
|
||||||
'use client';
|
|
||||||
|
|
||||||
import { createContext, useContext, useState } from 'react';
|
|
||||||
|
|
||||||
import { UserLevel } from '@/models/user';
|
|
||||||
import { contextOutsideScope } from '@/utils/labels';
|
|
||||||
|
|
||||||
interface IAccessModeContext {
|
|
||||||
accessLevel: UserLevel;
|
|
||||||
setAccessLevel: React.Dispatch<React.SetStateAction<UserLevel>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AccessContext = createContext<IAccessModeContext | null>(null);
|
|
||||||
export const useAccessMode = () => {
|
|
||||||
const context = useContext(AccessContext);
|
|
||||||
if (!context) {
|
|
||||||
throw new Error(contextOutsideScope('useAccessMode', 'AccessModeState'));
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AccessModeState = ({ children }: React.PropsWithChildren) => {
|
|
||||||
const [accessLevel, setAccessLevel] = useState<UserLevel>(UserLevel.READER);
|
|
||||||
return <AccessContext value={{ accessLevel, setAccessLevel }}>{children}</AccessContext>;
|
|
||||||
};
|
|
|
@ -103,7 +103,7 @@ export interface ITargetUsers {
|
||||||
/**
|
/**
|
||||||
* Represents user access mode.
|
* Represents user access mode.
|
||||||
*/
|
*/
|
||||||
export enum UserLevel {
|
export enum UserRole {
|
||||||
READER = 0,
|
READER = 0,
|
||||||
EDITOR,
|
EDITOR,
|
||||||
OWNER,
|
OWNER,
|
||||||
|
|
|
@ -19,13 +19,13 @@ import Button from '@/components/ui/Button';
|
||||||
import Divider from '@/components/ui/Divider';
|
import Divider from '@/components/ui/Divider';
|
||||||
import Dropdown from '@/components/ui/Dropdown';
|
import Dropdown from '@/components/ui/Dropdown';
|
||||||
import DropdownButton from '@/components/ui/DropdownButton';
|
import DropdownButton from '@/components/ui/DropdownButton';
|
||||||
import { useAccessMode } from '@/context/AccessModeContext';
|
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { useOSS } from '@/context/OssContext';
|
import { useOSS } from '@/context/OssContext';
|
||||||
import useDropdown from '@/hooks/useDropdown';
|
import useDropdown from '@/hooks/useDropdown';
|
||||||
import { UserLevel } from '@/models/user';
|
import { UserRole } from '@/models/user';
|
||||||
import { describeAccessMode, labelAccessMode } from '@/utils/labels';
|
import { useRoleStore } from '@/stores/role';
|
||||||
|
import { describeAccessMode as describeUserRole, labelAccessMode as labelUserRole } from '@/utils/labels';
|
||||||
|
|
||||||
import { useOssEdit } from './OssEditContext';
|
import { useOssEdit } from './OssEditContext';
|
||||||
|
|
||||||
|
@ -39,7 +39,8 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const model = useOSS();
|
const model = useOSS();
|
||||||
|
|
||||||
const { accessLevel, setAccessLevel } = useAccessMode();
|
const role = useRoleStore(state => state.role);
|
||||||
|
const setRole = useRoleStore(state => state.setRole);
|
||||||
|
|
||||||
const schemaMenu = useDropdown();
|
const schemaMenu = useDropdown();
|
||||||
const editMenu = useDropdown();
|
const editMenu = useDropdown();
|
||||||
|
@ -55,9 +56,9 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
|
||||||
controller.share();
|
controller.share();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleChangeMode(newMode: UserLevel) {
|
function handleChangeRole(newMode: UserRole) {
|
||||||
accessMenu.hide();
|
accessMenu.hide();
|
||||||
setAccessLevel(newMode);
|
setRole(newMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCreateNew() {
|
function handleCreateNew() {
|
||||||
|
@ -97,7 +98,7 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text='Удалить схему'
|
text='Удалить схему'
|
||||||
icon={<IconDestroy size='1rem' className='icon-red' />}
|
icon={<IconDestroy size='1rem' className='icon-red' />}
|
||||||
disabled={controller.isProcessing || accessLevel < UserLevel.OWNER}
|
disabled={controller.isProcessing || role < UserRole.OWNER}
|
||||||
onClick={handleDelete}
|
onClick={handleDelete}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -151,15 +152,15 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
|
||||||
noBorder
|
noBorder
|
||||||
noOutline
|
noOutline
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
title={`Режим ${labelAccessMode(accessLevel)}`}
|
title={`Режим ${labelUserRole(role)}`}
|
||||||
hideTitle={accessMenu.isOpen}
|
hideTitle={accessMenu.isOpen}
|
||||||
className='h-full pr-2'
|
className='h-full pr-2'
|
||||||
icon={
|
icon={
|
||||||
accessLevel === UserLevel.ADMIN ? (
|
role === UserRole.ADMIN ? (
|
||||||
<IconAdmin size='1.25rem' className='icon-primary' />
|
<IconAdmin size='1.25rem' className='icon-primary' />
|
||||||
) : accessLevel === UserLevel.OWNER ? (
|
) : role === UserRole.OWNER ? (
|
||||||
<IconOwner size='1.25rem' className='icon-primary' />
|
<IconOwner size='1.25rem' className='icon-primary' />
|
||||||
) : accessLevel === UserLevel.EDITOR ? (
|
) : role === UserRole.EDITOR ? (
|
||||||
<IconEditor size='1.25rem' className='icon-primary' />
|
<IconEditor size='1.25rem' className='icon-primary' />
|
||||||
) : (
|
) : (
|
||||||
<IconReader size='1.25rem' className='icon-primary' />
|
<IconReader size='1.25rem' className='icon-primary' />
|
||||||
|
@ -169,31 +170,31 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
|
||||||
/>
|
/>
|
||||||
<Dropdown isOpen={accessMenu.isOpen}>
|
<Dropdown isOpen={accessMenu.isOpen}>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={labelAccessMode(UserLevel.READER)}
|
text={labelUserRole(UserRole.READER)}
|
||||||
title={describeAccessMode(UserLevel.READER)}
|
title={describeUserRole(UserRole.READER)}
|
||||||
icon={<IconReader size='1rem' className='icon-primary' />}
|
icon={<IconReader size='1rem' className='icon-primary' />}
|
||||||
onClick={() => handleChangeMode(UserLevel.READER)}
|
onClick={() => handleChangeRole(UserRole.READER)}
|
||||||
/>
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={labelAccessMode(UserLevel.EDITOR)}
|
text={labelUserRole(UserRole.EDITOR)}
|
||||||
title={describeAccessMode(UserLevel.EDITOR)}
|
title={describeUserRole(UserRole.EDITOR)}
|
||||||
icon={<IconEditor size='1rem' className='icon-primary' />}
|
icon={<IconEditor size='1rem' className='icon-primary' />}
|
||||||
disabled={!model.isOwned && !model.schema?.editors.includes(user.id)}
|
disabled={!model.isOwned && !model.schema?.editors.includes(user.id)}
|
||||||
onClick={() => handleChangeMode(UserLevel.EDITOR)}
|
onClick={() => handleChangeRole(UserRole.EDITOR)}
|
||||||
/>
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={labelAccessMode(UserLevel.OWNER)}
|
text={labelUserRole(UserRole.OWNER)}
|
||||||
title={describeAccessMode(UserLevel.OWNER)}
|
title={describeUserRole(UserRole.OWNER)}
|
||||||
icon={<IconOwner size='1rem' className='icon-primary' />}
|
icon={<IconOwner size='1rem' className='icon-primary' />}
|
||||||
disabled={!model.isOwned}
|
disabled={!model.isOwned}
|
||||||
onClick={() => handleChangeMode(UserLevel.OWNER)}
|
onClick={() => handleChangeRole(UserRole.OWNER)}
|
||||||
/>
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={labelAccessMode(UserLevel.ADMIN)}
|
text={labelUserRole(UserRole.ADMIN)}
|
||||||
title={describeAccessMode(UserLevel.ADMIN)}
|
title={describeUserRole(UserRole.ADMIN)}
|
||||||
icon={<IconAdmin size='1rem' className='icon-primary' />}
|
icon={<IconAdmin size='1rem' className='icon-primary' />}
|
||||||
disabled={!user?.is_staff}
|
disabled={!user?.is_staff}
|
||||||
onClick={() => handleChangeMode(UserLevel.ADMIN)}
|
onClick={() => handleChangeRole(UserRole.ADMIN)}
|
||||||
/>
|
/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useState }
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
import { useAccessMode } from '@/context/AccessModeContext';
|
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useLibrary } from '@/context/LibraryContext';
|
import { useLibrary } from '@/context/LibraryContext';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
|
@ -30,8 +29,9 @@ import {
|
||||||
OperationID,
|
OperationID,
|
||||||
OperationType
|
OperationType
|
||||||
} from '@/models/oss';
|
} from '@/models/oss';
|
||||||
import { UserID, UserLevel } from '@/models/user';
|
import { UserID, UserRole } from '@/models/user';
|
||||||
import { usePreferencesStore } from '@/stores/preferences';
|
import { usePreferencesStore } from '@/stores/preferences';
|
||||||
|
import { useRoleStore } from '@/stores/role';
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
import { errors, information } from '@/utils/labels';
|
import { errors, information } from '@/utils/labels';
|
||||||
|
|
||||||
|
@ -96,14 +96,13 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const adminMode = usePreferencesStore(state => state.adminMode);
|
const adminMode = usePreferencesStore(state => state.adminMode);
|
||||||
const { accessLevel, setAccessLevel } = useAccessMode();
|
|
||||||
|
const role = useRoleStore(state => state.role);
|
||||||
|
const adjustRole = useRoleStore(state => state.adjustRole);
|
||||||
const model = useOSS();
|
const model = useOSS();
|
||||||
const library = useLibrary();
|
const library = useLibrary();
|
||||||
|
|
||||||
const isMutable = useMemo(
|
const isMutable = role > UserRole.READER && !model.schema?.read_only;
|
||||||
() => accessLevel > UserLevel.READER && !model.schema?.read_only,
|
|
||||||
[accessLevel, model.schema?.read_only]
|
|
||||||
);
|
|
||||||
|
|
||||||
const [showTooltip, setShowTooltip] = useState(true);
|
const [showTooltip, setShowTooltip] = useState(true);
|
||||||
|
|
||||||
|
@ -128,23 +127,13 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() =>
|
() =>
|
||||||
setAccessLevel(prev => {
|
adjustRole({
|
||||||
if (
|
isOwner: model.isOwned,
|
||||||
prev === UserLevel.EDITOR &&
|
isEditor: (user && model.schema?.editors.includes(user?.id)) ?? false,
|
||||||
(model.isOwned || user?.is_staff || (user && model.schema?.editors.includes(user.id)))
|
isStaff: user?.is_staff ?? false,
|
||||||
) {
|
adminMode: adminMode
|
||||||
return UserLevel.EDITOR;
|
|
||||||
} else if (user?.is_staff && (prev === UserLevel.ADMIN || adminMode)) {
|
|
||||||
return UserLevel.ADMIN;
|
|
||||||
} else if (model.isOwned) {
|
|
||||||
return UserLevel.OWNER;
|
|
||||||
} else if (user?.id && model.schema?.editors.includes(user?.id)) {
|
|
||||||
return UserLevel.EDITOR;
|
|
||||||
} else {
|
|
||||||
return UserLevel.READER;
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
[model.schema, setAccessLevel, model.isOwned, user, adminMode]
|
[model.schema, adjustRole, model.isOwned, user, adminMode]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSetLocation = useCallback(
|
const handleSetLocation = useCallback(
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
|
|
||||||
import { AccessModeState } from '@/context/AccessModeContext';
|
|
||||||
import { OssState } from '@/context/OssContext';
|
import { OssState } from '@/context/OssContext';
|
||||||
|
|
||||||
import OssTabs from './OssTabs';
|
import OssTabs from './OssTabs';
|
||||||
|
@ -10,11 +9,9 @@ import OssTabs from './OssTabs';
|
||||||
function OssPage() {
|
function OssPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
return (
|
return (
|
||||||
<AccessModeState>
|
|
||||||
<OssState itemID={params.id ?? ''}>
|
<OssState itemID={params.id ?? ''}>
|
||||||
<OssTabs />
|
<OssTabs />
|
||||||
</OssState>
|
</OssState>
|
||||||
</AccessModeState>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,13 +17,13 @@ import MiniButton from '@/components/ui/MiniButton';
|
||||||
import Overlay from '@/components/ui/Overlay';
|
import Overlay from '@/components/ui/Overlay';
|
||||||
import Tooltip from '@/components/ui/Tooltip';
|
import Tooltip from '@/components/ui/Tooltip';
|
||||||
import ValueIcon from '@/components/ui/ValueIcon';
|
import ValueIcon from '@/components/ui/ValueIcon';
|
||||||
import { useAccessMode } from '@/context/AccessModeContext';
|
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { useUsers } from '@/context/UsersContext';
|
import { useUsers } from '@/context/UsersContext';
|
||||||
import useDropdown from '@/hooks/useDropdown';
|
import useDropdown from '@/hooks/useDropdown';
|
||||||
import { ILibraryItemData, ILibraryItemEditor } from '@/models/library';
|
import { ILibraryItemData, ILibraryItemEditor } from '@/models/library';
|
||||||
import { UserID, UserLevel } from '@/models/user';
|
import { UserID, UserRole } from '@/models/user';
|
||||||
import { useLibrarySearchStore } from '@/stores/librarySearch';
|
import { useLibrarySearchStore } from '@/stores/librarySearch';
|
||||||
|
import { useRoleStore } from '@/stores/role';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
import { prompts } from '@/utils/labels';
|
import { prompts } from '@/utils/labels';
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ interface EditorLibraryItemProps {
|
||||||
|
|
||||||
function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemProps) {
|
function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemProps) {
|
||||||
const { getUserLabel, users } = useUsers();
|
const { getUserLabel, users } = useUsers();
|
||||||
const { accessLevel } = useAccessMode();
|
const role = useRoleStore(state => state.role);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const setLocation = useLibrarySearchStore(state => state.setLocation);
|
const setLocation = useLibrarySearchStore(state => state.setLocation);
|
||||||
|
@ -86,9 +86,7 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
|
||||||
value={item.location}
|
value={item.location}
|
||||||
title={controller.isAttachedToOSS ? 'Путь наследуется от ОСС' : 'Путь'}
|
title={controller.isAttachedToOSS ? 'Путь наследуется от ОСС' : 'Путь'}
|
||||||
onClick={controller.promptLocation}
|
onClick={controller.promptLocation}
|
||||||
disabled={
|
disabled={isModified || controller.isProcessing || controller.isAttachedToOSS || role < UserRole.OWNER}
|
||||||
isModified || controller.isProcessing || controller.isAttachedToOSS || accessLevel < UserLevel.OWNER
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -110,7 +108,7 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
|
||||||
value={getUserLabel(item.owner)}
|
value={getUserLabel(item.owner)}
|
||||||
title={controller.isAttachedToOSS ? 'Владелец наследуется от ОСС' : 'Владелец'}
|
title={controller.isAttachedToOSS ? 'Владелец наследуется от ОСС' : 'Владелец'}
|
||||||
onClick={ownerSelector.toggle}
|
onClick={ownerSelector.toggle}
|
||||||
disabled={isModified || controller.isProcessing || controller.isAttachedToOSS || accessLevel < UserLevel.OWNER}
|
disabled={isModified || controller.isProcessing || controller.isAttachedToOSS || role < UserRole.OWNER}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='sm:mb-1 flex justify-between items-center'>
|
<div className='sm:mb-1 flex justify-between items-center'>
|
||||||
|
@ -120,7 +118,7 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
|
||||||
icon={<IconEditor size='1.25rem' className='icon-primary' />}
|
icon={<IconEditor size='1.25rem' className='icon-primary' />}
|
||||||
value={item.editors.length}
|
value={item.editors.length}
|
||||||
onClick={controller.promptEditors}
|
onClick={controller.promptEditors}
|
||||||
disabled={isModified || controller.isProcessing || accessLevel < UserLevel.OWNER}
|
disabled={isModified || controller.isProcessing || role < UserRole.OWNER}
|
||||||
/>
|
/>
|
||||||
<Tooltip anchorSelect='#editor_stats' layer='z-modalTooltip'>
|
<Tooltip anchorSelect='#editor_stats' layer='z-modalTooltip'>
|
||||||
<InfoUsers items={item?.editors ?? []} prefix={prefixes.user_editors} header='Редакторы' />
|
<InfoUsers items={item?.editors ?? []} prefix={prefixes.user_editors} header='Редакторы' />
|
||||||
|
|
|
@ -5,10 +5,10 @@ import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
import Overlay from '@/components/ui/Overlay';
|
import Overlay from '@/components/ui/Overlay';
|
||||||
import { useAccessMode } from '@/context/AccessModeContext';
|
|
||||||
import { AccessPolicy, ILibraryItemEditor } from '@/models/library';
|
import { AccessPolicy, ILibraryItemEditor } from '@/models/library';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { UserLevel } from '@/models/user';
|
import { UserRole } from '@/models/user';
|
||||||
|
import { useRoleStore } from '@/stores/role';
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
|
|
||||||
interface ToolbarItemAccessProps {
|
interface ToolbarItemAccessProps {
|
||||||
|
@ -20,7 +20,7 @@ interface ToolbarItemAccessProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, controller }: ToolbarItemAccessProps) {
|
function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, controller }: ToolbarItemAccessProps) {
|
||||||
const { accessLevel } = useAccessMode();
|
const role = useRoleStore(state => state.role);
|
||||||
const policy = controller.schema?.access_policy ?? AccessPolicy.PRIVATE;
|
const policy = controller.schema?.access_policy ?? AccessPolicy.PRIVATE;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -28,7 +28,7 @@ function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, c
|
||||||
<Label text='Доступ' className='self-center select-none' />
|
<Label text='Доступ' className='self-center select-none' />
|
||||||
<div className='ml-auto cc-icons'>
|
<div className='ml-auto cc-icons'>
|
||||||
<SelectAccessPolicy
|
<SelectAccessPolicy
|
||||||
disabled={accessLevel <= UserLevel.EDITOR || controller.isProcessing || controller.isAttachedToOSS}
|
disabled={role <= UserRole.EDITOR || controller.isProcessing || controller.isAttachedToOSS}
|
||||||
value={policy}
|
value={policy}
|
||||||
onChange={newPolicy => controller.setAccessPolicy(newPolicy)}
|
onChange={newPolicy => controller.setAccessPolicy(newPolicy)}
|
||||||
/>
|
/>
|
||||||
|
@ -37,7 +37,7 @@ function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, c
|
||||||
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
||||||
icon={<VisibilityIcon value={visible} />}
|
icon={<VisibilityIcon value={visible} />}
|
||||||
onClick={toggleVisible}
|
onClick={toggleVisible}
|
||||||
disabled={accessLevel === UserLevel.READER || controller.isProcessing}
|
disabled={role === UserRole.READER || controller.isProcessing}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MiniButton
|
<MiniButton
|
||||||
|
@ -50,7 +50,7 @@ function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onClick={toggleReadOnly}
|
onClick={toggleReadOnly}
|
||||||
disabled={accessLevel === UserLevel.READER || controller.isProcessing}
|
disabled={role === UserRole.READER || controller.isProcessing}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<BadgeHelp topic={HelpTopic.ACCESS} className={PARAMETER.TOOLTIP_WIDTH} offset={4} />
|
<BadgeHelp topic={HelpTopic.ACCESS} className={PARAMETER.TOOLTIP_WIDTH} offset={4} />
|
||||||
|
|
|
@ -5,11 +5,11 @@ import BadgeHelp from '@/components/info/BadgeHelp';
|
||||||
import MiniSelectorOSS from '@/components/select/MiniSelectorOSS';
|
import MiniSelectorOSS from '@/components/select/MiniSelectorOSS';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
import Overlay from '@/components/ui/Overlay';
|
import Overlay from '@/components/ui/Overlay';
|
||||||
import { useAccessMode } from '@/context/AccessModeContext';
|
|
||||||
import { AccessPolicy, ILibraryItemEditor, LibraryItemType } from '@/models/library';
|
import { AccessPolicy, ILibraryItemEditor, LibraryItemType } from '@/models/library';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { IRSForm } from '@/models/rsform';
|
import { IRSForm } from '@/models/rsform';
|
||||||
import { UserLevel } from '@/models/user';
|
import { UserRole } from '@/models/user';
|
||||||
|
import { useRoleStore } from '@/stores/role';
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
import { prepareTooltip, tooltips } from '@/utils/labels';
|
import { prepareTooltip, tooltips } from '@/utils/labels';
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ interface ToolbarRSFormCardProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ToolbarRSFormCard({ modified, controller, onSubmit, onDestroy }: ToolbarRSFormCardProps) {
|
function ToolbarRSFormCard({ modified, controller, onSubmit, onDestroy }: ToolbarRSFormCardProps) {
|
||||||
const { accessLevel } = useAccessMode();
|
const role = useRoleStore(state => state.role);
|
||||||
const canSave = modified && !controller.isProcessing;
|
const canSave = modified && !controller.isProcessing;
|
||||||
|
|
||||||
const ossSelector = (() => {
|
const ossSelector = (() => {
|
||||||
|
@ -63,7 +63,7 @@ function ToolbarRSFormCard({ modified, controller, onSubmit, onDestroy }: Toolba
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Удалить схему'
|
title='Удалить схему'
|
||||||
icon={<IconDestroy size='1.25rem' className='icon-red' />}
|
icon={<IconDestroy size='1.25rem' className='icon-red' />}
|
||||||
disabled={!controller.isMutable || controller.isProcessing || accessLevel < UserLevel.OWNER}
|
disabled={!controller.isMutable || controller.isProcessing || role < UserRole.OWNER}
|
||||||
onClick={onDestroy}
|
onClick={onDestroy}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -31,14 +31,14 @@ import Button from '@/components/ui/Button';
|
||||||
import Divider from '@/components/ui/Divider';
|
import Divider from '@/components/ui/Divider';
|
||||||
import Dropdown from '@/components/ui/Dropdown';
|
import Dropdown from '@/components/ui/Dropdown';
|
||||||
import DropdownButton from '@/components/ui/DropdownButton';
|
import DropdownButton from '@/components/ui/DropdownButton';
|
||||||
import { useAccessMode } from '@/context/AccessModeContext';
|
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useGlobalOss } from '@/context/GlobalOssContext';
|
import { useGlobalOss } from '@/context/GlobalOssContext';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { useRSForm } from '@/context/RSFormContext';
|
import { useRSForm } from '@/context/RSFormContext';
|
||||||
import useDropdown from '@/hooks/useDropdown';
|
import useDropdown from '@/hooks/useDropdown';
|
||||||
import { AccessPolicy } from '@/models/library';
|
import { AccessPolicy } from '@/models/library';
|
||||||
import { UserLevel } from '@/models/user';
|
import { UserRole } from '@/models/user';
|
||||||
|
import { useRoleStore } from '@/stores/role';
|
||||||
import { describeAccessMode, labelAccessMode, tooltips } from '@/utils/labels';
|
import { describeAccessMode, labelAccessMode, tooltips } from '@/utils/labels';
|
||||||
|
|
||||||
import { OssTabID } from '../OssPage/OssTabs';
|
import { OssTabID } from '../OssPage/OssTabs';
|
||||||
|
@ -55,7 +55,8 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
|
||||||
const model = useRSForm();
|
const model = useRSForm();
|
||||||
const oss = useGlobalOss();
|
const oss = useGlobalOss();
|
||||||
|
|
||||||
const { accessLevel, setAccessLevel } = useAccessMode();
|
const role = useRoleStore(state => state.role);
|
||||||
|
const setRole = useRoleStore(state => state.setRole);
|
||||||
|
|
||||||
const schemaMenu = useDropdown();
|
const schemaMenu = useDropdown();
|
||||||
const editMenu = useDropdown();
|
const editMenu = useDropdown();
|
||||||
|
@ -126,9 +127,9 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
|
||||||
controller.inlineSynthesis();
|
controller.inlineSynthesis();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleChangeMode(newMode: UserLevel) {
|
function handleChangeMode(newMode: UserRole) {
|
||||||
accessMenu.hide();
|
accessMenu.hide();
|
||||||
setAccessLevel(newMode);
|
setRole(newMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCreateNew() {
|
function handleCreateNew() {
|
||||||
|
@ -198,7 +199,7 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text='Удалить схему'
|
text='Удалить схему'
|
||||||
icon={<IconDestroy size='1rem' className='icon-red' />}
|
icon={<IconDestroy size='1rem' className='icon-red' />}
|
||||||
disabled={controller.isProcessing || accessLevel < UserLevel.OWNER}
|
disabled={controller.isProcessing || role < UserRole.OWNER}
|
||||||
onClick={handleDelete}
|
onClick={handleDelete}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -310,15 +311,15 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
|
||||||
noBorder
|
noBorder
|
||||||
noOutline
|
noOutline
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
title={`Режим ${labelAccessMode(accessLevel)}`}
|
title={`Режим ${labelAccessMode(role)}`}
|
||||||
hideTitle={accessMenu.isOpen}
|
hideTitle={accessMenu.isOpen}
|
||||||
className='h-full pr-2'
|
className='h-full pr-2'
|
||||||
icon={
|
icon={
|
||||||
accessLevel === UserLevel.ADMIN ? (
|
role === UserRole.ADMIN ? (
|
||||||
<IconAdmin size='1.25rem' className='icon-primary' />
|
<IconAdmin size='1.25rem' className='icon-primary' />
|
||||||
) : accessLevel === UserLevel.OWNER ? (
|
) : role === UserRole.OWNER ? (
|
||||||
<IconOwner size='1.25rem' className='icon-primary' />
|
<IconOwner size='1.25rem' className='icon-primary' />
|
||||||
) : accessLevel === UserLevel.EDITOR ? (
|
) : role === UserRole.EDITOR ? (
|
||||||
<IconEditor size='1.25rem' className='icon-primary' />
|
<IconEditor size='1.25rem' className='icon-primary' />
|
||||||
) : (
|
) : (
|
||||||
<IconReader size='1.25rem' className='icon-primary' />
|
<IconReader size='1.25rem' className='icon-primary' />
|
||||||
|
@ -328,31 +329,31 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
|
||||||
/>
|
/>
|
||||||
<Dropdown isOpen={accessMenu.isOpen}>
|
<Dropdown isOpen={accessMenu.isOpen}>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={labelAccessMode(UserLevel.READER)}
|
text={labelAccessMode(UserRole.READER)}
|
||||||
title={describeAccessMode(UserLevel.READER)}
|
title={describeAccessMode(UserRole.READER)}
|
||||||
icon={<IconReader size='1rem' className='icon-primary' />}
|
icon={<IconReader size='1rem' className='icon-primary' />}
|
||||||
onClick={() => handleChangeMode(UserLevel.READER)}
|
onClick={() => handleChangeMode(UserRole.READER)}
|
||||||
/>
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={labelAccessMode(UserLevel.EDITOR)}
|
text={labelAccessMode(UserRole.EDITOR)}
|
||||||
title={describeAccessMode(UserLevel.EDITOR)}
|
title={describeAccessMode(UserRole.EDITOR)}
|
||||||
icon={<IconEditor size='1rem' className='icon-primary' />}
|
icon={<IconEditor size='1rem' className='icon-primary' />}
|
||||||
disabled={!model.isOwned && !model.schema?.editors.includes(user.id)}
|
disabled={!model.isOwned && !model.schema?.editors.includes(user.id)}
|
||||||
onClick={() => handleChangeMode(UserLevel.EDITOR)}
|
onClick={() => handleChangeMode(UserRole.EDITOR)}
|
||||||
/>
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={labelAccessMode(UserLevel.OWNER)}
|
text={labelAccessMode(UserRole.OWNER)}
|
||||||
title={describeAccessMode(UserLevel.OWNER)}
|
title={describeAccessMode(UserRole.OWNER)}
|
||||||
icon={<IconOwner size='1rem' className='icon-primary' />}
|
icon={<IconOwner size='1rem' className='icon-primary' />}
|
||||||
disabled={!model.isOwned}
|
disabled={!model.isOwned}
|
||||||
onClick={() => handleChangeMode(UserLevel.OWNER)}
|
onClick={() => handleChangeMode(UserRole.OWNER)}
|
||||||
/>
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={labelAccessMode(UserLevel.ADMIN)}
|
text={labelAccessMode(UserRole.ADMIN)}
|
||||||
title={describeAccessMode(UserLevel.ADMIN)}
|
title={describeAccessMode(UserRole.ADMIN)}
|
||||||
icon={<IconAdmin size='1rem' className='icon-primary' />}
|
icon={<IconAdmin size='1rem' className='icon-primary' />}
|
||||||
disabled={!user?.is_staff}
|
disabled={!user?.is_staff}
|
||||||
onClick={() => handleChangeMode(UserLevel.ADMIN)}
|
onClick={() => handleChangeMode(UserRole.ADMIN)}
|
||||||
/>
|
/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useState }
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
import { useAccessMode } from '@/context/AccessModeContext';
|
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { useRSForm } from '@/context/RSFormContext';
|
import { useRSForm } from '@/context/RSFormContext';
|
||||||
|
@ -49,8 +48,9 @@ import {
|
||||||
TermForm
|
TermForm
|
||||||
} from '@/models/rsform';
|
} from '@/models/rsform';
|
||||||
import { generateAlias } from '@/models/rsformAPI';
|
import { generateAlias } from '@/models/rsformAPI';
|
||||||
import { UserID, UserLevel } from '@/models/user';
|
import { UserID, UserRole } from '@/models/user';
|
||||||
import { usePreferencesStore } from '@/stores/preferences';
|
import { usePreferencesStore } from '@/stores/preferences';
|
||||||
|
import { useRoleStore } from '@/stores/role';
|
||||||
import { EXTEOR_TRS_FILE } from '@/utils/constants';
|
import { EXTEOR_TRS_FILE } from '@/utils/constants';
|
||||||
import { information, prompts } from '@/utils/labels';
|
import { information, prompts } from '@/utils/labels';
|
||||||
import { promptUnsaved } from '@/utils/utils';
|
import { promptUnsaved } from '@/utils/utils';
|
||||||
|
@ -143,13 +143,11 @@ export const RSEditState = ({
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const adminMode = usePreferencesStore(state => state.adminMode);
|
const adminMode = usePreferencesStore(state => state.adminMode);
|
||||||
const { accessLevel, setAccessLevel } = useAccessMode();
|
const role = useRoleStore(state => state.role);
|
||||||
|
const adjustRole = useRoleStore(state => state.adjustRole);
|
||||||
const model = useRSForm();
|
const model = useRSForm();
|
||||||
|
|
||||||
const isMutable = useMemo(
|
const isMutable = useMemo(() => role > UserRole.READER && !model.schema?.read_only, [role, model.schema?.read_only]);
|
||||||
() => accessLevel > UserLevel.READER && !model.schema?.read_only,
|
|
||||||
[accessLevel, model.schema?.read_only]
|
|
||||||
);
|
|
||||||
const isContentEditable = useMemo(() => isMutable && !model.isArchive, [isMutable, model.isArchive]);
|
const isContentEditable = useMemo(() => isMutable && !model.isArchive, [isMutable, model.isArchive]);
|
||||||
const canDeleteSelected = useMemo(
|
const canDeleteSelected = useMemo(
|
||||||
() => selected.length > 0 && selected.every(id => !model.schema?.cstByID.get(id)?.is_inherited),
|
() => selected.length > 0 && selected.every(id => !model.schema?.cstByID.get(id)?.is_inherited),
|
||||||
|
@ -199,23 +197,13 @@ export const RSEditState = ({
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() =>
|
() =>
|
||||||
setAccessLevel(prev => {
|
adjustRole({
|
||||||
if (
|
isOwner: model.isOwned,
|
||||||
prev === UserLevel.EDITOR &&
|
isEditor: (user && model.schema?.editors.includes(user?.id)) ?? false,
|
||||||
(model.isOwned || user?.is_staff || (user && model.schema?.editors.includes(user.id)))
|
isStaff: user?.is_staff ?? false,
|
||||||
) {
|
adminMode: adminMode
|
||||||
return UserLevel.EDITOR;
|
|
||||||
} else if (user?.is_staff && (prev === UserLevel.ADMIN || adminMode)) {
|
|
||||||
return UserLevel.ADMIN;
|
|
||||||
} else if (model.isOwned) {
|
|
||||||
return UserLevel.OWNER;
|
|
||||||
} else if (user?.id && model.schema?.editors.includes(user?.id)) {
|
|
||||||
return UserLevel.EDITOR;
|
|
||||||
} else {
|
|
||||||
return UserLevel.READER;
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
[model.schema, setAccessLevel, model.isOwned, user, adminMode]
|
[model.schema, adjustRole, model.isOwned, user, adminMode]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateSchema = useCallback(
|
const updateSchema = useCallback(
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
|
|
||||||
import { AccessModeState } from '@/context/AccessModeContext';
|
|
||||||
import { RSFormState } from '@/context/RSFormContext';
|
import { RSFormState } from '@/context/RSFormContext';
|
||||||
import useQueryStrings from '@/hooks/useQueryStrings';
|
import useQueryStrings from '@/hooks/useQueryStrings';
|
||||||
|
|
||||||
|
@ -13,11 +12,9 @@ function RSFormPage() {
|
||||||
const query = useQueryStrings();
|
const query = useQueryStrings();
|
||||||
const version = query.get('v') ?? undefined;
|
const version = query.get('v') ?? undefined;
|
||||||
return (
|
return (
|
||||||
<AccessModeState>
|
|
||||||
<RSFormState itemID={params.id ?? ''} versionID={version}>
|
<RSFormState itemID={params.id ?? ''} versionID={version}>
|
||||||
<RSTabs />
|
<RSTabs />
|
||||||
</RSFormState>
|
</RSFormState>
|
||||||
</AccessModeState>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { useAccessMode } from '@/context/AccessModeContext';
|
|
||||||
import useWindowSize from '@/hooks/useWindowSize';
|
import useWindowSize from '@/hooks/useWindowSize';
|
||||||
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
|
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
|
||||||
import { UserLevel } from '@/models/user';
|
import { UserRole } from '@/models/user';
|
||||||
import { useFitHeight } from '@/stores/appLayout';
|
import { useFitHeight } from '@/stores/appLayout';
|
||||||
|
import { useRoleStore } from '@/stores/role';
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
|
|
||||||
import ConstituentsSearch from './ConstituentsSearch';
|
import ConstituentsSearch from './ConstituentsSearch';
|
||||||
|
@ -27,8 +27,8 @@ interface ViewConstituentsProps {
|
||||||
|
|
||||||
function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit, isMounted }: ViewConstituentsProps) {
|
function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit, isMounted }: ViewConstituentsProps) {
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
const { accessLevel } = useAccessMode();
|
const role = useRoleStore(state => state.role);
|
||||||
const listHeight = useFitHeight(!isBottom ? '8.2rem' : accessLevel !== UserLevel.READER ? '42rem' : '35rem', '10rem');
|
const listHeight = useFitHeight(!isBottom ? '8.2rem' : role !== UserRole.READER ? '42rem' : '35rem', '10rem');
|
||||||
|
|
||||||
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);
|
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);
|
||||||
|
|
||||||
|
|
37
rsconcept/frontend/src/stores/role.ts
Normal file
37
rsconcept/frontend/src/stores/role.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
import { UserRole } from '@/models/user';
|
||||||
|
|
||||||
|
export interface RoleFlags {
|
||||||
|
isOwner: boolean;
|
||||||
|
isEditor: boolean;
|
||||||
|
isStaff: boolean;
|
||||||
|
adminMode: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RoleStore {
|
||||||
|
role: UserRole;
|
||||||
|
setRole: (value: UserRole) => void;
|
||||||
|
adjustRole: (flags: RoleFlags) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useRoleStore = create<RoleStore>()(set => ({
|
||||||
|
role: UserRole.READER,
|
||||||
|
setRole: value => set({ role: value }),
|
||||||
|
adjustRole: ({ isOwner, isEditor, isStaff, adminMode }: RoleFlags) =>
|
||||||
|
set(state => {
|
||||||
|
if (state.role === UserRole.EDITOR && (isOwner || isStaff || isEditor)) {
|
||||||
|
return { role: UserRole.EDITOR };
|
||||||
|
}
|
||||||
|
if (isStaff && (state.role === UserRole.ADMIN || adminMode)) {
|
||||||
|
return { role: UserRole.ADMIN };
|
||||||
|
}
|
||||||
|
if (isOwner) {
|
||||||
|
return { role: UserRole.OWNER };
|
||||||
|
}
|
||||||
|
if (isEditor) {
|
||||||
|
return { role: UserRole.EDITOR };
|
||||||
|
}
|
||||||
|
return { role: UserRole.READER };
|
||||||
|
})
|
||||||
|
}));
|
|
@ -19,7 +19,7 @@ import {
|
||||||
RSErrorType,
|
RSErrorType,
|
||||||
TokenID
|
TokenID
|
||||||
} from '@/models/rslang';
|
} from '@/models/rslang';
|
||||||
import { UserLevel } from '@/models/user';
|
import { UserRole } from '@/models/user';
|
||||||
|
|
||||||
import { PARAMETER } from './constants';
|
import { PARAMETER } from './constants';
|
||||||
|
|
||||||
|
@ -822,31 +822,31 @@ export function describeSubstitutionError(error: ISubstitutionErrorDescription):
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves label for {@link UserLevel}.
|
* Retrieves label for {@link UserRole}.
|
||||||
*/
|
*/
|
||||||
export function labelAccessMode(mode: UserLevel): string {
|
export function labelAccessMode(mode: UserRole): string {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case UserLevel.READER: return 'Читатель';
|
case UserRole.READER: return 'Читатель';
|
||||||
case UserLevel.EDITOR: return 'Редактор';
|
case UserRole.EDITOR: return 'Редактор';
|
||||||
case UserLevel.OWNER: return 'Владелец';
|
case UserRole.OWNER: return 'Владелец';
|
||||||
case UserLevel.ADMIN: return 'Администратор';
|
case UserRole.ADMIN: return 'Администратор';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves description for {@link UserLevel}.
|
* Retrieves description for {@link UserRole}.
|
||||||
*/
|
*/
|
||||||
export function describeAccessMode(mode: UserLevel): string {
|
export function describeAccessMode(mode: UserRole): string {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case UserLevel.READER:
|
case UserRole.READER:
|
||||||
return 'Режим запрещает редактирование';
|
return 'Режим запрещает редактирование';
|
||||||
case UserLevel.EDITOR:
|
case UserRole.EDITOR:
|
||||||
return 'Режим редактирования';
|
return 'Режим редактирования';
|
||||||
case UserLevel.OWNER:
|
case UserRole.OWNER:
|
||||||
return 'Режим владельца';
|
return 'Режим владельца';
|
||||||
case UserLevel.ADMIN:
|
case UserRole.ADMIN:
|
||||||
return 'Режим администратора';
|
return 'Режим администратора';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user